Mouse_draw_circle.py

本文介绍了一个使用Python和OpenCV实现的简单绘图应用,该应用允许用户通过鼠标点击和拖动来绘制矩形或圆形,并可以通过调整颜色来改变绘图的颜色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# -*- coding: utf-8 -*-
"""
Created on Sun Jan 5 14:59:58 2014
@author: duan
"""
import cv2
import numpy as np

def nothing(x):
    pass

# 当鼠标按下时变为True
drawing=False

# 如果mode 为true 绘制矩形。按下'm' 变成绘制曲线。
mode=True
ix,iy=-1,-1

# 创建回调函数
def draw_circle(event,x,y,flags,param):
    r=cv2.getTrackbarPos('R','image')
    g=cv2.getTrackbarPos('G','image')
    b=cv2.getTrackbarPos('B','image')
    color=(b,g,r)
    global ix,iy,drawing,mode
    # 当按下左键是返回起始位置坐标
    if event==cv2.EVENT_LBUTTONDOWN:
        drawing=True
        ix,iy=x,y
    # 当鼠标左键按下并移动是绘制图形。event 可以查看移动,flag 查看是否按下
    elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_FLAG_LBUTTON:
        if drawing==True:
            if mode==True:
                cv2.rectangle(img,(ix,iy),(x,y),color,-1)
            else:
                # 绘制圆圈,小圆点连在一起就成了线,3 代表了笔画的粗细
                cv2.circle(img,(x,y),3,color,-1)
                # 下面注释掉的代码是起始点为圆心,起点到终点为半径的
                # r=int(np.sqrt((x-ix)**2+(y-iy)**2))
                # cv2.circle(img,(x,y),r,(0,0,255),-1)
    # 当鼠标松开停止绘画。
    elif event==cv2.EVENT_LBUTTONUP:
        drawing==False
        # if mode==True:
            # cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
        # else:
            # cv2.circle(img,(x,y),5,(0,0,255),-1)

img=np.zeros((512,512,3),np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
cv2.setMouseCallback('image',draw_circle)
while(1):
    cv2.imshow('image',img)

    k=cv2.waitKey(1)&0xFF
    if k==ord('m'):
        mode=not mode
    elif k==27:
        break
        

修改这段代码以支持打包 import os import cv2 import numpy as np import screeninfo from PIL import Image, ImageDraw, ImageFont import time from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import os import logging # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') def resource_path(relative_path): """获取资源绝对路径,支持PyInstaller打包后运行""" try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) class EnhancedImageViewer: """增强版图像查看器,支持亮度查看(Lux值)""" def __init__(self, image_path, title="图像查看器", base_output_name=None): self.image_path = image_path self.original_image = cv2.imread(image_path) if self.original_image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 保存基础输出名称 self.base_output_name = base_output_name if base_output_name else \ os.path.splitext(os.path.basename(image_path))[0] # 获取灰度图像用于亮度分析 self.gray_image = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) # 获取屏幕尺寸 try: screen = screeninfo.get_monitors()[0] self.max_width = screen.width - 100 self.max_height = screen.height - 100 except: self.max_width = 1620 self.max_height = 880 # 初始缩放状态 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 # 创建显示图像 self.display_image = self.original_image.copy() self.resized_display = self.resize_to_fit(self.original_image) # 创建窗口 self.window_name = title cv2.namedWindow(self.window_name, cv2.WINDOW_NORMAL) cv2.setMouseCallback(self.window_name, self.mouse_callback) # 更新显示 self.update_display() def resize_to_fit(self, image): """调整图像尺寸以适应屏幕""" height, width = image.shape[:2] scale_width = self.max_width / width scale_height = self.max_height / height self.scale_factor = min(scale_width, scale_height, 1.0) new_width = int(width * self.scale_factor) new_height = int(height * self.scale_factor) if self.scale_factor < 1.0: return cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA) return image.copy() def put_chinese_text(self, image, text, position, font_size=20, color=(255, 255, 255)): """在图像上添加中文文本""" if image is None or image.size == 0: return image # 确保图像是3通道的 if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # 转换为PIL图像 (RGB格式) pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_img) # 使用支持中文的字体 try: font = ImageFont.truetype("simhei.ttf", font_size) except: try: font = ImageFont.truetype("msyh.ttc", font_size) except: try: font = ImageFont.truetype("/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", font_size) except: font = ImageFont.load_default() # 添加文本 draw.text(position, text, font=font, fill=color) # 转换回OpenCV格式 return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) def update_display(self): """更新显示图像""" # 缩放小于等于1.0时直接显示 self.display_image = self.resized_display.copy() # 添加帮助文本 help_text = "左键:查看亮度(Lux) | ESC:退出 | R:重置 | S:保存" self.display_image = self.put_chinese_text( self.display_image, help_text, (10, 20), font_size=20, color=(0, 255, 0) ) # 显示图像 cv2.imshow(self.window_name, self.display_image) def mouse_callback(self, event, x, y, flags, param): """鼠标事件回调函数 - 仅保留左键点击功能""" # 鼠标左键点击 - 显示亮度值(Lux) if event == cv2.EVENT_LBUTTONDOWN: # 计算原始图像坐标 orig_x, orig_y = self.convert_coords(x, y) # 获取原始图像中的灰度值 if 0 <= orig_x < self.gray_image.shape[1] and 0 <= orig_y < self.gray_image.shape[0]: gray_value = self.gray_image[orig_y, orig_x] # 将灰度值转换为Lux值 (0-255范围映射到0-740 Lux) lux_value = int((gray_value / 255.0) * 740) # 在当前显示图像上添加标记和信息 display_copy = self.display_image.copy() cv2.circle(display_copy, (x, y), 5, (0, 0, 255), -1) # 计算文本位置(避免遮挡) text_x = x + 10 text_y = y - 10 # 如果靠近右侧边缘,向左移动文本 if text_x > self.display_image.shape[1] - 250: text_x = x - 250 # 如果靠近底部边缘,向上移动文本 if text_y < 30: text_y = y + 20 # 添加中文文本(显示Lux值) text = f"位置: ({orig_x}, {orig_y}) 亮度: {lux_value} Lux" display_copy = self.put_chinese_text( display_copy, text, (text_x, text_y), font_size=18, color=(0, 255, 255) ) cv2.imshow(self.window_name, display_copy) def convert_coords(self, x, y): """将显示坐标转换为原始图像坐标""" # 缩小或正常状态下的坐标转换 orig_x = int(x / self.scale_factor) orig_y = int(y / self.scale_factor) # 确保坐标在有效范围内 orig_x = max(0, min(orig_x, self.original_image.shape[1] - 1)) orig_y = max(0, min(orig_y, self.original_image.shape[0] - 1)) return orig_x, orig_y def run(self): """运行查看器主循环""" while True: key = cv2.waitKey(1) & 0xFF if key == 27: # ESC退出 break elif key == ord('r'): # 重置视图 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 self.resized_display = self.resize_to_fit(self.original_image) self.update_display() elif key == ord('s'): # 保存当前视图 # 使用基础输出名称生成截图文件名 screenshot_path = f"{self.base_output_name}_screenshot.png" cv2.imwrite(screenshot_path, self.display_image) print(f"截图已保存为 {screenshot_path}") cv2.destroyAllWindows() def preprocess_image(image_path): """图像预处理""" image = cv2.imread(image_path) if image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 转换为灰度图并降噪 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (9, 9), 0) # 对比度增强 clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(8, 8)) enhanced = clahe.apply(blurred) return image, gray, enhanced def analyze_intensity(enhanced): """亮度分析""" min_intensity = np.min(enhanced) max_intensity = np.max(enhanced) normalized = cv2.normalize(enhanced.astype('float'), None, 0, 1, cv2.NORM_MINMAX) return min_intensity, max_intensity, normalized def generate_heatmap(image, normalized): """生成热力图""" heatmap = cv2.applyColorMap((normalized * 255).astype(np.uint8), cv2.COLORMAP_JET) blended = cv2.addWeighted(image, 0.7, heatmap, 0.3, 0) return heatmap, blended def process_contours(image, enhanced, min_intensity, max_intensity, num_levels=7): """处理等高线""" height, width = image.shape[:2] contour_image = np.zeros_like(image) color_intensity_map = [] # 计算亮度层级 levels = np.linspace(min_intensity, max_intensity, num_levels).astype(np.uint8) kernel = np.ones((3, 3), np.uint8) for i, level in enumerate(levels): # 创建当前亮度层级的掩膜 lower_val = max(int(level) - 10, 0) upper_val = min(int(level) + 10, 255) mask = cv2.inRange(enhanced, lower_val, upper_val) # 形态学处理 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 查找等高线 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 计算颜色(冷色调到暖色调渐变) normalized_level = (level - min_intensity) / (max_intensity - min_intensity) if normalized_level < 0.5: hue = 120 + 60 * normalized_level * 2 else: hue = 60 * (1 - (normalized_level - 0.5) * 2) hue = np.clip(hue, 0, 180) # 转换为BGR颜色 color = cv2.cvtColor(np.uint8([[[hue, 255, 255]]]), cv2.COLOR_HSV2BGR)[0][0] color = tuple(map(int, color)) # 存储颜色-亮度映射 # 将灰度值转换为Lux值 (0-255范围映射到0-740 Lux) lux_value = int((level / 255.0) * 740) color_intensity_map.append((color, lux_value)) # 绘制等高线 cv2.drawContours(contour_image, contours, -1, color, 2) return contour_image, color_intensity_map def create_color_bar(image, color_intensity_map, min_intensity, max_intensity): """创建颜色条 - 显示Lux值""" height, width = image.shape[:2] bar_width = int(width * 0.03) bar_height = int(height * 0.3) bar_x = width - int(width * 0.05) - bar_width bar_y = int(height * 0.05) # 生成颜色条 color_bar = np.zeros((bar_height, bar_width, 3), dtype=np.uint8) for i in range(bar_height): idx = int((1 - i / bar_height) * (len(color_intensity_map) - 1)) color_bar[i, :] = color_intensity_map[idx][0] # 添加到图像 result = image.copy() result[bar_y:bar_y + bar_height, bar_x:bar_x + bar_width] = color_bar # 添加边框 cv2.rectangle(result, (bar_x, bar_y), (bar_x + bar_width, bar_y + bar_height), (255, 255, 255), 1) # 添加刻度和标签(显示Lux值) num_ticks = 5 min_lux = 0 max_lux = 740 for i, pos in enumerate(np.linspace(0, bar_height, num_ticks)): y_pos = int(bar_y + pos) cv2.line(result, (bar_x - 5, y_pos), (bar_x, y_pos), (255, 255, 255), 1) # 计算标签位置 value = int(min_lux + (max_lux - min_lux) * (1 - pos / bar_height)) text_x = bar_x - 50 text_y = y_pos + (15 if i == 0 else -10 if i == num_ticks - 1 else 0) # 添加带描边的文本 cv2.putText(result, f"{value} Lux", (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, f"{value} Lux", (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) # 添加标题 cv2.putText(result, 'Light Intensity (Lux)', (bar_x - 150, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, 'Light Intensity (Lux)', (bar_x - 150, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) return result class ImageHandler(FileSystemEventHandler): def __init__(self, processing_function): self.processing_function = processing_function self.supported_exts = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff'] def on_created(self, event): """当新文件创建时触发""" if not event.is_directory: file_path = event.src_path if self._is_image(file_path): logging.info(f"检测到新图片: {file_path}") # 等待文件完全写入(根据实际需求调整) time.sleep(0.5) self.processing_function(file_path) def _is_image(self, file_path): """检查是否为支持的图片格式""" ext = os.path.splitext(file_path)[1].lower() return ext in self.supported_exts def start_monitoring(path_to_watch, processing_function): """启动文件夹监控服务""" event_handler = ImageHandler(processing_function) observer = Observer() observer.schedule(event_handler, path_to_watch, recursive=False) observer.start() logging.info(f"开始监控文件夹: {path_to_watch}") try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join() def main(image_path): """主处理流程""" try: # 从路径中提取基础文件名(不含扩展名) base_name = os.path.splitext(os.path.basename(image_path))[0] # 1. 图像预处理 image, gray, enhanced = preprocess_image(image_path) # 2. 亮度分析 min_intensity, max_intensity, normalized = analyze_intensity(enhanced) # 3. 生成热力图 heatmap, blended = generate_heatmap(image, normalized) # 4. 处理等高线 contour_image, color_intensity_map = process_contours( image, enhanced, min_intensity, max_intensity ) # 5. 创建最终结果(显示Lux值) base_image = cv2.addWeighted(image, 0.7, contour_image, 0.3, 0) # 使用固定的0-740 Lux范围 min_lux = 0 max_lux = 740 final_result = create_color_bar(base_image, color_intensity_map, min_lux, max_lux) # 保存结果(使用基础文件名作为前缀) cv2.imwrite(f"{base_name}_result.png", final_result) cv2.imwrite(f"{base_name}_Contours.png", contour_image) cv2.imwrite(f"{base_name}_Heatmap.png", heatmap) cv2.imwrite(f"{base_name}_Blended.png", blended) print(f"处理完成! 结果已保存为 {base_name}_*.png") # 启动交互式查看器(传递基础文件名) viewer = EnhancedImageViewer('4.jpg', 'photo_view', base_output_name=base_name) viewer.run() except Exception as e: print(f"处理过程中发生错误: {str(e)}") if __name__ == "__main__": # 修改这里的图片路径 image_path = '4.jpg' main(image_path)
07-15
增加一个选择项,用户可按照是否存在异常亮度区域选择照片进行亮度查看 import os import cv2 import numpy as np import screeninfo from PIL import Image, ImageDraw, ImageFont class EnhancedImageViewer: """增强版图像查看器,支持亮度查看(Lux值)""" def __init__(self, image_array, title="Image View", base_output_name=None): # 直接使用图像数组而不是文件路径 self.original_image = image_array if self.original_image is None: raise ValueError("无法加载图像数组") # 保存基础输出名称 self.base_output_name = base_output_name if base_output_name else "output" # 获取灰度图像用于亮度分析 self.gray_image = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) # 获取屏幕尺寸 try: screen = screeninfo.get_monitors()[0] self.max_width = screen.width - 100 self.max_height = screen.height - 100 except: self.max_width = 1080 self.max_height = 1080 # 初始缩放状态 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 # 创建显示图像 self.display_image = self.original_image.copy() self.resized_display = self.resize_to_fit(self.original_image) # 创建窗口 self.window_name = title cv2.namedWindow(self.window_name, cv2.WINDOW_NORMAL) cv2.setMouseCallback(self.window_name, self.mouse_callback) # 更新显示 self.update_display() def resize_to_fit(self, image): """调整图像尺寸以适应屏幕""" height, width = image.shape[:2] scale_width = self.max_width / width scale_height = self.max_height / height self.scale_factor = min(scale_width, scale_height, 1.0) new_width = int(width * self.scale_factor) new_height = int(height * self.scale_factor) if self.scale_factor < 1.0: return cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA) return image.copy() def put_chinese_text(self, image, text, position, font_size=20, color=(255, 255, 255)): """在图像上添加中文文本""" if image is None or image.size == 0: return image # 确保图像是3通道的 if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # 转换为PIL图像 (RGB格式) pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_img) # 使用支持中文的字体 try: font = ImageFont.truetype("simhei.ttf", font_size) except: try: font = ImageFont.truetype("msyh.ttc", font_size) except: try: font = ImageFont.truetype("/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", font_size) except: font = ImageFont.load_default() # 添加文本 draw.text(position, text, font=font, fill=color) # 转换回OpenCV格式 return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) def update_display(self): """更新显示图像""" # 缩放小于等于1.0时直接显示 self.display_image = self.resized_display.copy() # 添加帮助文本 help_text = "左键:查看亮度(Lux) | ESC:退出 | R:重置 | S:保存" self.display_image = self.put_chinese_text( self.display_image, help_text, (10, 20), font_size=20, color=(0, 255, 0) ) # 显示图像 cv2.imshow(self.window_name, self.display_image) def mouse_callback(self, event, x, y, flags, param): """鼠标事件回调函数 - 仅保留左键点击功能""" # 鼠标左键点击 - 显示亮度值(Lux) if event == cv2.EVENT_LBUTTONDOWN: # 计算原始图像坐标 orig_x, orig_y = self.convert_coords(x, y) # 获取原始图像中的灰度值 if 0 <= orig_x < self.gray_image.shape[1] and 0 <= orig_y < self.gray_image.shape[0]: gray_value = self.gray_image[orig_y, orig_x] # 将灰度值转换为Lux值 (0-255范围映射到Lux) lux_value = int((gray_value / 255.0) * 660) # 在当前显示图像上添加标记和信息 display_copy = self.display_image.copy() cv2.circle(display_copy, (x, y), 5, (0, 0, 255), -1) # 计算文本位置(避免遮挡) text_x = x + 10 text_y = y - 10 # 如果靠近右侧边缘,向左移动文本 if text_x > self.display_image.shape[1] - 280: text_x = x - 280 # 如果靠近底部边缘,向上移动文本 if text_y < 30: text_y = y + 20 # 添加中文文本(显示Lux值) text = f"位置: ({orig_x}, {orig_y}) 亮度: {lux_value} Lux" display_copy = self.put_chinese_text( display_copy, text, (text_x, text_y), font_size=18, color=(0, 255, 255) ) cv2.imshow(self.window_name, display_copy) def convert_coords(self, x, y): """将显示坐标转换为原始图像坐标""" # 缩小或正常状态下的坐标转换 orig_x = int(x / self.scale_factor) orig_y = int(y / self.scale_factor) # 确保坐标在有效范围内 orig_x = max(0, min(orig_x, self.original_image.shape[1] - 1)) orig_y = max(0, min(orig_y, self.original_image.shape[0] - 1)) return orig_x, orig_y def run(self): """运行查看器主循环""" while True: key = cv2.waitKey(1) & 0xFF if key == 27: # ESC退出 break elif key == ord('r'): # 重置视图 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 self.resized_display = self.resize_to_fit(self.original_image) self.update_display() elif key == ord('s'): # 保存当前视图 # 使用基础输出名称生成截图文件名 screenshot_path = f"{self.base_output_name}_screenshot.png" cv2.imwrite(screenshot_path, self.display_image) print(f"截图已保存为 {screenshot_path}") cv2.destroyAllWindows() def apply_gaussian_blur(image, kernel_size=(5, 5), sigma=1): """应用高斯模糊""" return cv2.GaussianBlur(image, kernel_size, sigma) def preprocess_image(image_path): """图像预处理""" image = cv2.imread(image_path) if image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 应用高斯模糊 blurred_image = apply_gaussian_blur(image) # 转换为灰度图并降噪 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred_gray = cv2.GaussianBlur(gray, (3, 3), 1) # 对比度增强 clahe = cv2.createCLAHE(clipLimit=9.0, tileGridSize=(21, 21)) enhanced = clahe.apply(blurred_gray) return image, gray, enhanced, blurred_image def analyze_intensity(enhanced): """亮度分析""" min_intensity = np.min(enhanced) max_intensity = np.max(enhanced) normalized = cv2.normalize(enhanced.astype('float'), None, 0, 1, cv2.NORM_MINMAX) return min_intensity, max_intensity, normalized def generate_heatmap(image, normalized): """生成热力图""" heatmap = cv2.applyColorMap((normalized * 255).astype(np.uint8), cv2.COLORMAP_JET) blended = cv2.addWeighted(image, 0.7, heatmap, 0.3, 0) return heatmap, blended def process_contours(image, enhanced, min_intensity, max_intensity, num_levels=7): """处理等高线""" height, width = image.shape[:2] contour_image = np.zeros_like(image) color_intensity_map = [] # 计算亮度层级 levels = np.linspace(min_intensity, max_intensity, num_levels).astype(np.uint8) kernel = np.ones((3, 3), np.uint8) for i, level in enumerate(levels): # 创建当前亮度层级的掩膜 lower_val = max(int(level) - 10, 0) upper_val = min(int(level) + 10, 255) mask = cv2.inRange(enhanced, lower_val, upper_val) # 形态学处理 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 查找等高线 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 计算颜色(冷色调到暖色调渐变) normalized_level = (level - min_intensity) / (max_intensity - min_intensity) if normalized_level < 0.5: hue = 120 + 60 * normalized_level * 2 else: hue = 60 * (1 - (normalized_level - 0.5) * 2) hue = np.clip(hue, 0, 180) # 转换为BGR颜色 color = cv2.cvtColor(np.uint8([[[hue, 255, 255]]]), cv2.COLOR_HSV2BGR)[0][0] color = tuple(map(int, color)) # 存储颜色-亮度映射 # 将灰度值转换为Lux值 (0-255范围映射到 Lux) lux_value = int((level / 255.0) * 660) color_intensity_map.append((color, lux_value)) # 绘制等高线 cv2.drawContours(contour_image, contours, -1, color, 2) return contour_image, color_intensity_map def create_color_bar(image, color_intensity_map, min_intensity, max_intensity): """创建颜色条 - 显示Lux值""" height, width = image.shape[:2] bar_width = int(width * 0.01) bar_height = int(height * 0.3) bar_x = width - int(width * 0.05) - bar_width bar_y = int(height * 0.05) # 生成颜色条 color_bar = np.zeros((bar_height, bar_width, 3), dtype=np.uint8) for i in range(bar_height): idx = int((1 - i / bar_height) * (len(color_intensity_map) - 1)) color_bar[i, :] = color_intensity_map[idx][0] # 添加到图像 result = image.copy() result[bar_y:bar_y + bar_height, bar_x:bar_x + bar_width] = color_bar # 添加边框 cv2.rectangle(result, (bar_x, bar_y), (bar_x + bar_width, bar_y + bar_height), (255, 255, 255), 1) # 添加刻度和标签(显示Lux值) num_ticks = 5 min_lux = 0 max_lux = 2200 for i, pos in enumerate(np.linspace(0, bar_height, num_ticks)): y_pos = int(bar_y + pos) cv2.line(result, (bar_x - 5, y_pos), (bar_x, y_pos), (255, 255, 255), 1) # 计算标签位置 value = int(min_lux + (max_lux - min_lux) * (1 - pos / bar_height)) text_x = bar_x - 50 text_y = y_pos + (15 if i == 0 else -10 if i == num_ticks - 1 else 0) # 添加带描边的文本 cv2.putText(result, f"{value} Lux", (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, f"{value} Lux", (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) # 添加标题 cv2.putText(result, 'Light Intensity (Lux)', (bar_x - 150, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, 'Light Intensity (Lux)', (bar_x - 150, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) return result def main(image_path): """主处理流程""" try: # 从路径中提取基础文件名(不含扩展名) base_name = os.path.splitext(os.path.basename(image_path))[0] # 1. 图像预处理 image, gray, enhanced, blurred_image = preprocess_image(image_path) # 2. 亮度分析 min_intensity, max_intensity, normalized = analyze_intensity(enhanced) # 3. 生成热力图 heatmap, blended = generate_heatmap(image, normalized) # 4. 处理等高线 contour_image, color_intensity_map = process_contours( image, enhanced, min_intensity, max_intensity ) # 5. 创建最终结果(显示Lux值) base_image = cv2.addWeighted(image, 0.7, contour_image, 0.3, 0) # 使用固定的 Lux范围 min_lux = 0 max_lux = 660 final_result = create_color_bar(base_image, color_intensity_map, min_lux, max_lux) # 保存结果(使用基础文件名作为前缀) cv2.imwrite(f"{base_name}_result.png", final_result) cv2.imwrite(f"{base_name}_Contours.png", contour_image) cv2.imwrite(f"{base_name}_Heatmap.png", heatmap) cv2.imwrite(f"{base_name}_Blended.png", blended) cv2.imwrite(f"{base_name}_blurred_image.png", blurred_image) print(f"处理完成! 结果已保存为 {base_name}_*.png") # 启动交互式查看器(传递高斯模糊图像数组) viewer = EnhancedImageViewer(blurred_image, "Image View", base_output_name=base_name) viewer.run() except Exception as e: print(f"处理过程中发生错误: {str(e)}") if __name__ == "__main__": # 修改这里的图片路径 image_path = 'photo_031.jpg' main(image_path) 将程序中的亮度变成用户在主程序修改或者根据提示修改
最新发布
07-23
import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont # 参数设置 image_path = '2.jpg' num_levels = 7 #等高线层数 contour_thickness = 2 #等高线粗细 blur_size = (9, 9) # 统一使用高斯模糊尺寸 clahe_params = {'clipLimit': 4.0, 'tileGridSize': (8, 8)} #可优化对比度增强效果 # 1. 图像预处理 def preprocess_image(image_path): image = cv2.imread(image_path) if image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 转换为灰度图并降噪 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, blur_size, 0) # 对比度增强 clahe = cv2.createCLAHE(**clahe_params) enhanced = clahe.apply(blurred) # 存储图像数据 image_data['original'] = image image_data['display'] = image.copy() image_data['gray'] = gray image_data['enhanced'] = enhanced return image, enhanced,image_data['original'],image_data['display'],image_data['gray'],image_data['enhanced'] # 2. 亮度分析 def analyze_intensity(enhanced): min_intensity = np.min(enhanced) max_intensity = np.max(enhanced) normalized = cv2.normalize(enhanced.astype('float'), None, 0, 1, cv2.NORM_MINMAX) return min_intensity, max_intensity, normalized # 3. 热力图生成 def generate_heatmap(image, normalized): heatmap = cv2.applyColorMap((normalized * 255).astype(np.uint8), cv2.COLORMAP_JET) blended = cv2.addWeighted(image, 0.7, heatmap, 0.3, 0) return heatmap, blended # 4. 等高线处理 def process_contours(image, enhanced, min_intensity, max_intensity, num_levels): height, width = image.shape[:2] contour_image = np.zeros_like(image) color_intensity_map = [] # 计算亮度层级 levels = np.linspace(min_intensity, max_intensity, num_levels).astype(np.uint8) kernel = np.ones((3, 3), np.uint8) for i, level in enumerate(levels): # 创建当前亮度层级的掩膜 lower_val = max(int(level) - 10, 0) upper_val = min(int(level) + 10, 255) mask = cv2.inRange(enhanced, lower_val, upper_val) # 形态学处理 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 查找等高线 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 计算颜色(冷色调到暖色调渐变) normalized_level = (level - min_intensity) / (max_intensity - min_intensity) if normalized_level < 0.5: hue = 120 + 60 * normalized_level * 2 else: hue = 60 * (1 - (normalized_level - 0.5) * 2) hue = np.clip(hue, 0, 180) # 转换为BGR颜色 color = cv2.cvtColor(np.uint8([[[hue, 255, 255]]]), cv2.COLOR_HSV2BGR)[0][0] color = tuple(map(int, color)) # 存储颜色-亮度映射 color_intensity_map.append((color, level)) # 绘制等高线 cv2.drawContours(contour_image, contours, -1, color, contour_thickness) return contour_image, color_intensity_map # 5. 创建颜色条 def create_color_bar(image, color_intensity_map, min_intensity, max_intensity): height, width = image.shape[:2] bar_width = int(width * 0.03) bar_height = int(height * 0.3) bar_x = width - int(width * 0.05) - bar_width bar_y = int(height * 0.05) # 生成颜色条 color_bar = np.zeros((bar_height, bar_width, 3), dtype=np.uint8) for i in range(bar_height): idx = int((1 - i / bar_height) * (len(color_intensity_map) - 1)) color_bar[i, :] = color_intensity_map[idx][0] # 添加到图像 result = image.copy() result[bar_y:bar_y + bar_height, bar_x:bar_x + bar_width] = color_bar # 添加边框 cv2.rectangle(result, (bar_x, bar_y), (bar_x + bar_width, bar_y + bar_height), (255, 255, 255), 1) # 添加刻度和标签 num_ticks = 5 for i, pos in enumerate(np.linspace(0, bar_height, num_ticks)): y_pos = int(bar_y + pos) cv2.line(result, (bar_x - 5, y_pos), (bar_x, y_pos), (255, 255, 255), 1) # 计算标签位置 value = int(min_intensity + (max_intensity - min_intensity) * (1 - pos / bar_height)) text_x = bar_x - 50 text_y = y_pos + (15 if i == 0 else -10 if i == num_ticks - 1 else 0) # 添加带描边的文本 cv2.putText(result, str(value), (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, str(value), (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) # 添加标题 cv2.putText(result, 'Light Intensity', (bar_x - 100, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, 'Light Intensity', (bar_x - 100, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) return result # 全局变量存储图像数据和状态 current_point = None image_data = { 'original': None, 'gray': None, 'display': None } def mouse_callback(event, x, y, flags, param): """鼠标事件回调函数,用于捕获点击位置并显示亮度值""" global current_point if event == cv2.EVENT_LBUTTONDOWN: # 保存当前选定的点 current_point = (x, y) # 获取该点的亮度值 if image_data['gray'] is not None: intensity = image_data['gray'][y, x] print(f"点 ({x}, {y}) 的亮度值: {intensity}") # 在图像上显示亮度值 display_image = image_data['display'].copy() # 绘制标记点 cv2.circle(display_image, (x, y), 5, (0, 0, 255), -1) # 红色圆点 # 绘制坐标和亮度文本 text = f"({x}, {y}): {intensity}" cv2.putText(display_image, text, (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2) # 显示更新后的图像 cv2.imshow("Interactive Light Intensity", display_image) image_data['display'] = display_image def put_chinese_text(image, text, position, font_size=20, color=(255, 255, 255)): """ 在图像上添加中文文本 参数: image: OpenCV图像 (BGR格式) text: 要添加的中文文本 position: 文本位置 (x, y) font_size: 字体大小 color: 文本颜色 (B, G, R) 返回: 添加文本后的OpenCV图像 """ # 转换为PIL图像 (RGB格式) pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_img) # 使用支持中文的字体 try: # 尝试使用系统字体 font = ImageFont.truetype("simhei.ttf", font_size) except: try: # 尝试其他常见中文字体 font = ImageFont.truetype("msyh.ttc", font_size) except: # 如果找不到中文字体,使用默认字体(可能不支持中文) font = ImageFont.load_default() print("警告:未找到中文字体,中文可能显示为方框") # 添加文本 draw.text(position, text, font=font, fill=color) # 转换回OpenCV格式 return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) # 主流程 def main(): # 1. 图像预处理 image, enhanced ,image_data['original'],image_data['display'],image_data['gray'],image_data['enhanced'] = preprocess_image(image_path) # 2. 亮度分析 min_intensity, max_intensity, normalized = analyze_intensity(enhanced) # 3. 生成热力图 heatmap, blended = generate_heatmap(image, normalized) # 4. 处理等高线 contour_image, color_intensity_map = process_contours( image, enhanced, min_intensity, max_intensity, num_levels ) pil_img = put_chinese_text(image, text, position, font_size=20, color=(255, 255, 255)) # 5. 创建最终结果 base_image = cv2.addWeighted(image, 0.7, contour_image, 0.3, 0) final_result = create_color_bar(base_image, color_intensity_map, min_intensity, max_intensity) # 保存结果 cv2.imwrite("result.png", final_result) cv2.imwrite("Contours.png", contour_image) cv2.imwrite('Heatmap.png', heatmap) cv2.imwrite('Blended.png', blended) print("处理完成! 对比度图像结果已保存") # 创建窗口并设置鼠标回调 cv2.namedWindow("Interactive Light Intensity") cv2.setMouseCallback("Interactive Light Intensity", mouse_callback) # 显示初始图像 cv2.imshow("Interactive Light Intensity", pil_img) # 添加帮助文本 help_text = "点击图像任意位置查看亮度值 | 按ESC退出" cv2.putText(image_data['display'], help_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) # 主循环 while True: key = cv2.waitKey(1) & 0xFF if key == 27: # ESC键退出 break cv2.destroyAllWindows() if __name__ == "__main__": main() 中文文本显示添加失败
07-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值