活动介绍

from PIL import Image, ImageDraw # 将图片平移并旋转 gray2 = Image.fromarray(src) width, height = gray2.size # 计算中心点和X轴角度 center = (max_point[0], max_point[1]) angle = np.arctan2(point2[1] - max_point[1], point2[0] - max_point[0]) * 180 / np.pi img_translated = gray2.transform((width, height), Image.AFFINE, (1, 0, center[0] - width/2, 0, 1, center[1] - height/2), resample=Image.BICUBIC) img_translated_rotated = img_translated.rotate(angle, resample=Image.BICUBIC, expand=True) #img_translated_rotated.show() #裁剪 img4 = Image.fromarray(src) width1, height1 = img4.size width2, height2 = img_translated_rotated.size left = (width2 - width1 )/2 top = (height2 - height1 )/2 right = (width2 - width1 )/2 + width1 bottom = (height2 - height1 )/2 + height1 cropped_image = img_translated_rotated.crop((left, top, right, bottom )) import cv2 GRID_STEP = distance/2 # 设置1010栅格(暂时尝试) grid_num_x = 10 grid_num_y = 10 def transform_point_set(points, max_point, distance, angle): # 平移向量 translation_vector = np.array([distance * np.cos(anglenp.pi/180), distance * np.sin(anglenp.pi/180)]) # 旋转矩阵 rotation_matrix = np.array([[np.cos(anglenp.pi/180), -np.sin(anglenp.pi/180)], [np.sin(anglenp.pi/180), np.cos(angle*np.pi/180)]]) # 将点集转换为 numpy 数组 point_array = np.array(points) max_point_array = np.array(max_point) # 对点集进行平移和旋转 point_array = (point_array - max_point_array) @ rotation_matrix + max_point_array + translation_vector # 将 numpy 数组转换为列表 points2 = point_array.tolist() return points2 points2 = transform_point_set(points, max_point, distance, angle) print(points2) #第2.5部分(用作确认检验) from PIL import Image, ImageDraw #裁剪 img4 = Image.fromarray(src) width1, height1 = img4.size width2, height2 = img_translated_rotated.size left = (width2 - width1 )/2 top = (height2 - height1 )/2 right = (width2 - width1 )/2 + width1 bottom = (height2 - height1 )/2 + height1 cropped_image = img_translated_rotated.crop((left, top, right, bottom )) # 导入图片() img_array = np.asarray(cropped_image) img = Image.fromarray(img_array) draw = ImageDraw.Draw(img) for point in point

时间: 2023-06-18 14:07:58 浏览: 202
这是一段 Python 代码,主要是对图片进行平移和旋转,并进行裁剪,然后将一组点坐标进行平移和旋转后输出。具体实现过程中,代码使用了 PIL 库和 OpenCV 库。首先通过 PIL 库中的 Image 类将源图片转换为灰度图像 gray2,然后计算出中心点和旋转角度,通过 transform 和 rotate 方法对图片进行平移和旋转操作。接着通过 crop 方法进行裁剪,将裁剪后的图片转换为 numpy 数组 img_array。最后使用 PIL 库中的 ImageDraw 类和 for 循环对一组点坐标进行平移和旋转,并输出平移和旋转后的点坐标。
相关问题

from PIL import Image, ImageDraw # 将图片平移并旋转 gray2 = Image.fromarray(src) width, height = gray2.size # 计算中心点和X轴角度 center = (max_point[0], max_point[1]) angle = np.arctan2(point2[1] - max_point[1], point2[0] - max_point[0]) * 180 / np.pi img_translated = gr

ay2.transform((width, height), Image.AFFINE, (1, 0, -center[0], 0, 1, -center[1])) # 平移图片 img_rotated = img_translated.rotate(angle) # 旋转图片 draw = ImageDraw.Draw(img_rotated) # 获取绘图对象 draw.line([max_point, point2], fill='red', width=2) # 绘制直线 img_rotated.show() # 显示处理后的图片 以上代码是对一张图片进行平移和旋转,并在图片上绘制一条直线。首先利用PIL库中的Image类将数组转换成图片对象,然后计算中心点和旋转角度,利用transform()方法平移图片,利用rotate()方法旋转图片,最后利用Draw类绘制直线。最后通过show()方法显示处理后的图片。

#第四部分 旋转图片 from PIL import Image, ImageDraw # 将图片平移并旋转 gray2 = Image.fromarray(src) width, height = gray2.size # 计算中心点和X轴角度 center = (max_point[0], max_point[1]) angle = np.arctan2(point2[1] - max_point[1], point2[0] - max_point[0]) * 180 / np.pi img_translated = gray2.transform((width, height), Image.AFFINE, (1, 0, center[0] - width/2, 0, 1, center[1] - height/2), resample=Image.BICUBIC) img_translated_rotated = img_translated.rotate(angle, resample=Image.BICUBIC, expand=True) #img_translated_rotated.show() import cv2 GRID_STEP = distance/2 # 设置10*10栅格(暂时尝试) grid_num_x = 10 grid_num_y = 10 def transform_point_set(points, max_point, distance, angle): # 平移向量 translation_vector = np.array([distance * np.cos(angle*np.pi/180), distance * np.sin(angle*np.pi/180)]) # 旋转矩阵 rotation_matrix = np.array([[np.cos(angle*np.pi/180), -np.sin(angle*np.pi/180)], [np.sin(angle*np.pi/180), np.cos(angle*np.pi/180)]]) # 将点集转换为 numpy 数组 point_array = np.array(points) max_point_array = np.array(max_point) # 对点集进行平移和旋转 point_array = (point_array - max_point_array) @ rotation_matrix + max_point_array + translation_vector # 将 numpy 数组转换为列表 points2 = point_array.tolist() return points2 操作之后点和再图上原本的位置不再重合,请分析原因

经过平移和旋转操作后,图像的像素位置发生了变化,导致点集与原本的位置不再重合。这是因为平移和旋转操作会改变图像的坐标系和像素位置,因此点集也需要进行相应的坐标变换才能与图像对应。在代码中,函数 transform_point_set 实现了对点集进行平移和旋转变换的操作,但可能存在一些细节问题导致变换不准确,需要进一步检查和调试。
阅读全文

相关推荐

import platform import cv2 import numpy as np import screeninfo from PIL import Image, ImageDraw, ImageFont class EnhancedImageViewer: """增强版图像查看器,支持缩放、平移和亮度查看""" def __init__(self, image_path, title="图像查看器"): self.image_path = image_path self.original_image = cv2.imread(image_path) if self.original_image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 获取灰度图像用于亮度分析 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 = 1280 self.max_height = 720 # 初始缩放状态 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 self.pan_start = None # 创建显示图像 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): """更新显示图像""" # 根据缩放和平移调整显示区域 if self.scale_factor > 1.0: # 缩放大于1.0时需要裁剪 height, width = self.original_image.shape[:2] scaled_width = int(width * self.scale_factor) scaled_height = int(height * self.scale_factor) # 创建缩放后的图像 scaled_image = cv2.resize(self.original_image, (scaled_width, scaled_height), interpolation=cv2.INTER_LINEAR) # 应用平移偏移 x1 = max(0, min(self.offset_x, scaled_width - self.max_width)) y1 = max(0, min(self.offset_y, scaled_height - self.max_height)) x2 = min(x1 + self.max_width, scaled_width) y2 = min(y1 + self.max_height, scaled_height) # 裁剪显示区域 self.display_image = scaled_image[y1:y2, x1:x2] else: # 缩放小于等于1.0时直接显示 self.display_image = self.resized_display.copy() # 添加帮助文本 help_text = "左键:查看亮度 | 滚轮:缩放 | 中键拖动:平移 | 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): """鼠标事件回调函数""" # 鼠标左键点击 - 显示亮度值 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]: intensity = self.gray_image[orig_y, orig_x] # 在当前显示图像上添加标记和信息 display_copy = self.display_image.copy() cv2.circle(display_copy, (x, y), 5, (0, 0, 255), -1) # 添加中文文本 text = f"位置: ({orig_x}, {orig_y}) 亮度: {intensity}" display_copy = self.put_chinese_text( display_copy, text, (x + 10, y - 10), font_size=18, color=(0, 255, 255) ) cv2.imshow(self.window_name, display_copy) # 鼠标滚轮缩放 - 跨平台处理 elif event == cv2.EVENT_MOUSEWHEEL: # 获取操作系统类型 os_type = platform.system() # Windows系统处理 if os_type == 'Windows': # Windows上flags包含滚轮增量 wheel_delta = flags if wheel_delta > 0: # 向上滚动 - 放大 self.zoom_at_point(x, y, 1.1) else: # 向下滚动 - 缩小 self.zoom_at_point(x, y, 0.9) # Linux/Mac系统处理 else: # Linux/Mac上flags表示方向 if flags > 0: # 向上滚动 - 放大 self.zoom_at_point(x, y, 1.1) else: # 向下滚动 - 缩小 self.zoom_at_point(x, y, 0.9) # 鼠标中键拖动平移 elif event == cv2.EVENT_MBUTTONDOWN: self.pan_start = (x, y) elif event == cv2.EVENT_MOUSEMOVE and flags & cv2.EVENT_FLAG_MBUTTON: if self.pan_start: dx = x - self.pan_start[0] dy = y - self.pan_start[1] self.offset_x += dx * (1 / self.scale_factor) self.offset_y += dy * (1 / self.scale_factor) self.pan_start = (x, y) self.update_display() elif event == cv2.EVENT_MBUTTONUP: self.pan_start = None def zoom_at_point(self, x, y, zoom_factor): """以指定点为中心缩放图像""" # 保存当前缩放前的原始坐标 orig_x, orig_y = self.convert_coords(x, y) # 更新缩放因子 new_scale = self.scale_factor * zoom_factor # 限制缩放范围 if new_scale < 0.1: new_scale = 0.1 elif new_scale > 10: new_scale = 10 # 计算缩放后该点在新坐标系中的位置 if self.scale_factor > 1.0: # 当前是放大状态 self.offset_x += orig_x * (1 / self.scale_factor - 1 / new_scale) self.offset_y += orig_y * (1 / self.scale_factor - 1 / new_scale) else: # 当前是缩小或正常状态 self.offset_x = orig_x * (1 - 1 / new_scale) self.offset_y = orig_y * (1 - 1 / new_scale) self.scale_factor = new_scale self.update_display() def convert_coords(self, x, y): """将显示坐标转换为原始图像坐标""" if self.scale_factor > 1.0: # 放大状态下的坐标转换 orig_x = int((x + self.offset_x) / self.scale_factor) orig_y = int((y + self.offset_y) / self.scale_factor) else: # 缩小或正常状态下的坐标转换 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'): # 保存当前视图 cv2.imwrite("viewer_screenshot.png", self.display_image) print("截图已保存为 viewer_screenshot.png") cv2.destroyAllWindows() # 参数设置 image_path = '2.jpg' num_levels = 7 # 等高线层数 contour_thickness = 2 # 等高线粗细 blur_size = (9, 9) # 高斯模糊尺寸 clahe_params = {'clipLimit': 4.0, 'tileGridSize': (8, 8)} # 对比度增强参数 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) 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): """处理等高线""" 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 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 def main(): """主处理流程""" try: # 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, num_levels ) # 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("处理完成! 对比度图像结果已保存") # 启动交互式查看器 viewer = EnhancedImageViewer("result.png", "亮度等高线分析") viewer.run() except Exception as e: print(f"处理过程中发生错误: {str(e)}") if __name__ == "__main__": main() 输出的图片名称应该为原始图片名称+现在的名称

import cv2 import numpy as np from paddleocr import PaddleOCR import re import traceback from PIL import Image, ImageDraw, ImageFont # 初始化PaddleOCR ocr = PaddleOCR( use_textline_orientation=True, lang="ch", # det_algorithm="DB", # 固定使用 DB 检测算法(更稳定) text_det_thresh=0, # 降低检测阈值,让检测框更贴合文字 text_det_unclip_ratio=0.5, # 缩小文本框扩展比例,避免框过大 text_det_box_thresh=0.5, # 过滤小文本框的阈值 # det_model_dir='D:\DaiMaGongJu\PaddleOCR\models\ch_PP-OCRv4_det_server_infer', ) def preprocess_image(image): """图像预处理以提高识别率""" gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8)) gray = clahe.apply(gray) # gray = cv2.adaptiveThreshold( # gray, # 255, # cv2.ADAPTIVE_THRESH_GAUSSIAN_C, # cv2.THRESH_BINARY,11,2) # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # gray = cv2.dilate(gray, kernel, iterations=1) # gray = cv2.erode(gray, kernel, iterations=1) gray = cv2.GaussianBlur(gray, (3, 3), 0) return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) def shrink_box(pts, shrink_ratio=0.03): """按比例收缩检测框""" x_min = np.min(pts[:, 0, 0]) y_min = np.min(pts[:, 0, 1]) x_max = np.max(pts[:, 0, 0]) y_max = np.max(pts[:, 0, 1]) width = x_max - x_min height = y_max - y_min x_min += width * shrink_ratio x_max -= width * shrink_ratio y_min += height * shrink_ratio y_max -= height * shrink_ratio return np.array([[[x_min, y_min]], [[x_max, y_min]], [[x_max, y_max]], [[x_min, y_max]]], dtype=np.int32) def draw_text_with_pil(image, text, position, color, font_size=14): """使用PIL库绘制中文文本""" # 转换为PIL图像 pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_image) # 尝试加载中文字体,可根据系统调整字体路径 try: font = ImageFont.truetype("simhei.ttf", font_size, encoding="utf-8") except IOError: # 如果找不到指定字体,使用默认字体 font = ImageFont.load_default() # 绘制文本 draw.text(position, text, font=font, fill=tuple(reversed(color))) # 转回OpenCV格式 return cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) def detect_text_with_colored_boxes(image_path, output_path=None): """使用PaddleOCR识别文本并绘制彩色边界框""" image = cv2.imread(image_path) if image is None: raise FileNotFoundError(f"无法读取图像: {image_path}") if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) try: processed_image = preprocess_image(image) result = ocr.predict(processed_image) color_map = { 'title': (0, 0, 255), 'body': (0, 255, 0), 'footer': (255, 0, 0), 'number': (255, 255, 0), 'default': (0, 255, 255) } recognized_text = [] if isinstance(result, list): if len(result) > 0 and isinstance(result[0], dict): for item in result: if 'rec_texts' in item and 'dt_polys' in item and 'rec_scores' in item: texts = item['rec_texts'] coords_list = item['dt_polys'] scores = item['rec_scores'] for i in range(min(len(texts), len(coords_list), len(scores))): text = texts[i].strip() coords = coords_list[i] confidence = scores[i] if len(text) > 0 and confidence > 0.3: pts = np.array(coords, np.int32).reshape((-1, 1, 2)) category = classify_text(text, i) color = color_map.get(category, color_map['default']) cv2.polylines(image, [pts], True, color, 2) # 计算文本位置 x, y = pts[0][0][0], pts[0][0][1] y = max(y - 15, 15) # 调整位置,确保文本不超出图像 # 使用PIL绘制文本 image = draw_text_with_pil(image, text, (x, y - 15), color) recognized_text.append({ 'text': text, 'category': category, 'confidence': confidence, 'coordinates': coords }) else: print(f"无法解析的结果格式: {list(item.keys())[:5]}...") else: for i, item in enumerate(result): if isinstance(item, list) and len(item) >= 2: coords = item[0] text_info = item[1] if isinstance(text_info, (list, tuple)) and len(text_info) >= 2: text = text_info[0].strip() confidence = text_info[1] if len(text) > 0 and confidence > 0.3: pts = np.array(coords, np.int32).reshape((-1, 1, 2)) category = classify_text(text, i) color = color_map.get(category, color_map['default']) cv2.polylines(image, [pts], True, color, 2) x, y = pts[0][0][0], pts[0][0][1] y = max(y - 15, 15) image = draw_text_with_pil(image, text, (x, y - 15), color) recognized_text.append({ 'text': text, 'category': category, 'confidence': confidence, 'coordinates': coords }) else: print(f"跳过格式异常的结果项: {item[:50]}...") else: print(f"OCR返回非预期格式: {type(result)}") if output_path: cv2.imwrite(output_path, image) return recognized_text, image except Exception as e: print(f"OCR处理过程中出错: {str(e)}") traceback.print_exc() raise def classify_text(text, idx): """根据文本内容和位置分类""" if idx < 3 and len(text) > 2: return 'title' elif re.match(r'^[\d\.¥¥%,]+$', text): return 'number' elif any(keyword in text for keyword in ['合计', '日期', '谢谢', '总计', '欢迎', '下次光临']): return 'footer' else: return 'body' if __name__ == "__main__": input_image = 'small.jpg' output_image = 'document_ocr2.jpg' try: print("开始OCR识别...") results, processed_image = detect_text_with_colored_boxes(input_image, output_image) print(f"识别完成,共识别出 {len(results)} 个文本区域") for item in results: print(f"[{item['category']}] {item['text']} (置信度: {item['confidence']:.2f})") cv2.imshow('OCR Result', processed_image) cv2.waitKey(0) cv2.destroyAllWindows() except FileNotFoundError as e: print(f"文件错误: {e}") except Exception as e: print(f"处理过程中出错: {e}") 该代码在识别图片中的文字时,识别框与文字不贴合,改进代码

zip

最新推荐

recommend-type

langchain4j-anthropic-spring-boot-starter-0.31.0.jar中文文档.zip

1、压缩文件中包含: 中文文档、jar包下载地址、Maven依赖、Gradle依赖、源代码下载地址。 2、使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 3、特殊说明: (1)本文档为人性化翻译,精心制作,请放心使用; (2)只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; (3)不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 4、温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件。 5、本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册。
recommend-type

TMS320F28335电机控制程序详解:BLDC、PMSM无感有感及异步VF源代码与开发资料

TMS320F28335这款高性能数字信号处理器(DSP)在电机控制领域的应用,涵盖了BLDC(无刷直流电机)、PMSM(永磁同步电机)的无感有感控制以及异步VF(变频调速)程序。文章不仅解释了各类型的电机控制原理,还提供了完整的开发资料,包括源代码、原理图和说明文档,帮助读者深入了解其工作原理和编程技巧。 适合人群:从事电机控制系统开发的技术人员,尤其是对TMS320F28335感兴趣的工程师。 使用场景及目标:适用于需要掌握TMS320F28335在不同电机控制应用场景下具体实现方法的专业人士,旨在提高他们对该微控制器的理解和实际操作能力。 其他说明:文中提供的开发资料为读者提供了从硬件到软件的全面支持,有助于加速项目开发进程并提升系统性能。
recommend-type

基于爬山搜索法的风力发电MPPT控制Simulink仿真:定步长与变步长算法性能对比 - 爬山搜索法 最新版

基于爬山搜索法的风力发电最大功率点追踪(MPPT)控制的Simulink仿真模型,重点比较了定步长和变步长算法在不同风速条件下的表现。文中展示了两种算法的具体实现方法及其优缺点。定步长算法虽然结构简单、计算量小,但在风速突变时响应较慢,存在明显的稳态振荡。相比之下,变步长算法能够根据功率变化动态调整步长,表现出更快的响应速度和更高的精度,尤其在风速突变时优势明显。实验数据显示,变步长算法在风速从8m/s突增至10m/s的情况下,仅用0.3秒即可稳定,功率波动范围仅为±15W,而定步长算法则需要0.8秒,功率波动达到±35W。 适合人群:从事风力发电研究的技术人员、对MPPT控制感兴趣的工程技术人员以及相关专业的高校师生。 使用场景及目标:适用于风力发电系统的设计与优化,特别是需要提高系统响应速度和精度的场合。目标是在不同风速条件下,选择合适的MPPT算法以最大化风能利用率。 其他说明:文章还讨论了定步长算法在风速平稳情况下的优势,提出了根据不同应用场景灵活选择或组合使用这两种算法的建议。
recommend-type

基于MatlabSimulink的风电场调频策略研究:虚拟惯性、超速减载与下垂控制的协调优化

内容概要:本文详细探讨了在Matlab/Simulink环境下,针对风电场调频的研究,尤其是双馈风机调频策略的应用及其与其他调频策略的协调工作。文中介绍了三种主要的调频策略——虚拟惯性、超速减载和下垂控制,并基于三机九节点系统进行了改进,模拟了四组风电机组的协同调频过程。研究指出,虚拟惯性的应用虽然可以提供短期频率支持,但也可能导致频率二次跌落的问题。因此,需要通过超速减载和下垂控制来进行补偿,以维持电网的稳定。此外,文章还展示了在变风速条件下,风电机组对电网频率支撑能力的显著提升,尤其是在高比例风电并网渗透的情况下,频率最低点提高了50%,验证了调频策略的有效性。 适合人群:从事电力系统、风电场运营管理和调频技术研发的专业人士,以及对风电调频感兴趣的科研人员和技术爱好者。 使用场景及目标:适用于希望深入理解风电场调频机制及其优化方法的人群。目标是掌握不同调频策略的工作原理及其协调工作的关键点,提高风电场的运行效率和稳定性。 其他说明:本文通过具体的案例研究和仿真数据,展示了调频策略的实际效果,强调了合理运用调频策略对于风电场稳定运行的重要意义。同时,也为未来的风电调频技术创新提供了理论依据和实践经验。
recommend-type

三菱QL系列PLC在3C-FPC组装机中的定位与伺服控制及触摸屏应用解析

三菱Q系列和L系列PLC在3C-FPC组装机中的具体应用,涵盖硬件架构、软件编程以及实际操作技巧。主要内容包括:使用QX42数字输入模块和QY42P晶体管输出模块进行高效信号处理;采用JE系列伺服控制系统实现高精度四轴联动;利用SFC(顺序功能图)和梯形图编程方法构建稳定可靠的控制系统;通过触摸屏实现多用户管理和权限控制;并分享了一些实用的调试和维护技巧,如流水线节拍控制和工程师模式进入方法。最终,该系统的设备综合效率(OEE)达到了92%以上。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对三菱PLC有初步了解并希望深入了解其高级应用的人群。 使用场景及目标:适用于需要高精度、高效能的工业生产设备控制场合,旨在帮助用户掌握三菱PLC及其相关组件的应用技能,提高生产效率和产品质量。 其他说明:文中提供了详细的编程实例和操作指南,有助于读者更好地理解和实践。同时提醒使用者在调试过程中应注意伺服刚性参数调整,避免不必要的机械损伤。
recommend-type

Visual C++.NET编程技术实战指南

根据提供的文件信息,可以生成以下知识点: ### Visual C++.NET编程技术体验 #### 第2章 定制窗口 - **设置窗口风格**:介绍了如何通过编程自定义窗口的外观和行为。包括改变窗口的标题栏、边框样式、大小和位置等。这通常涉及到Windows API中的`SetWindowLong`和`SetClassLong`函数。 - **创建六边形窗口**:展示了如何创建一个具有特殊形状边界的窗口,这类窗口不遵循标准的矩形形状。它需要使用`SetWindowRgn`函数设置窗口的区域。 - **创建异形窗口**:扩展了定制窗口的内容,提供了创建非标准形状窗口的方法。这可能需要创建一个不规则的窗口区域,并将其应用到窗口上。 #### 第3章 菜单和控制条高级应用 - **菜单编程**:讲解了如何创建和修改菜单项,处理用户与菜单的交互事件,以及动态地添加或删除菜单项。 - **工具栏编程**:阐述了如何使用工具栏,包括如何创建工具栏按钮、分配事件处理函数,并实现工具栏按钮的响应逻辑。 - **状态栏编程**:介绍了状态栏的创建、添加不同类型的指示器(如文本、进度条等)以及状态信息的显示更新。 - **为工具栏添加皮肤**:展示了如何为工具栏提供更加丰富的视觉效果,通常涉及到第三方的控件库或是自定义的绘图代码。 #### 第5章 系统编程 - **操作注册表**:解释了Windows注册表的结构和如何通过程序对其进行读写操作,这对于配置软件和管理软件设置非常关键。 - **系统托盘编程**:讲解了如何在系统托盘区域创建图标,并实现最小化到托盘、从托盘恢复窗口的功能。 - **鼠标钩子程序**:介绍了钩子(Hook)技术,特别是鼠标钩子,如何拦截和处理系统中的鼠标事件。 - **文件分割器**:提供了如何将文件分割成多个部分,并且能够重新组合文件的技术示例。 #### 第6章 多文档/多视图编程 - **单文档多视**:展示了如何在同一个文档中创建多个视图,这在文档编辑软件中非常常见。 #### 第7章 对话框高级应用 - **实现无模式对话框**:介绍了无模式对话框的概念及其应用场景,以及如何实现和管理无模式对话框。 - **使用模式属性表及向导属性表**:讲解了属性表的创建和使用方法,以及如何通过向导性质的对话框引导用户完成多步骤的任务。 - **鼠标敏感文字**:提供了如何实现点击文字触发特定事件的功能,这在阅读器和编辑器应用中很有用。 #### 第8章 GDI+图形编程 - **图像浏览器**:通过图像浏览器示例,展示了GDI+在图像处理和展示中的应用,包括图像的加载、显示以及基本的图像操作。 #### 第9章 多线程编程 - **使用全局变量通信**:介绍了在多线程环境下使用全局变量进行线程间通信的方法和注意事项。 - **使用Windows消息通信**:讲解了通过消息队列在不同线程间传递信息的技术,包括发送消息和处理消息。 - **使用CriticalSection对象**:阐述了如何使用临界区(CriticalSection)对象防止多个线程同时访问同一资源。 - **使用Mutex对象**:介绍了互斥锁(Mutex)的使用,用以同步线程对共享资源的访问,保证资源的安全。 - **使用Semaphore对象**:解释了信号量(Semaphore)对象的使用,它允许一个资源由指定数量的线程同时访问。 #### 第10章 DLL编程 - **创建和使用Win32 DLL**:介绍了如何创建和链接Win32动态链接库(DLL),以及如何在其他程序中使用这些DLL。 - **创建和使用MFC DLL**:详细说明了如何创建和使用基于MFC的动态链接库,适用于需要使用MFC类库的场景。 #### 第11章 ATL编程 - **简单的非属性化ATL项目**:讲解了ATL(Active Template Library)的基础使用方法,创建一个不使用属性化组件的简单项目。 - **使用ATL开发COM组件**:详细阐述了使用ATL开发COM组件的步骤,包括创建接口、实现类以及注册组件。 #### 第12章 STL编程 - **list编程**:介绍了STL(标准模板库)中的list容器的使用,讲解了如何使用list实现复杂数据结构的管理。 #### 第13章 网络编程 - **网上聊天应用程序**:提供了实现基本聊天功能的示例代码,包括客户端和服务器的通信逻辑。 - **简单的网页浏览器**:演示了如何创建一个简单的Web浏览器程序,涉及到网络通信和HTML解析。 - **ISAPI服务器扩展编程**:介绍了如何开发ISAPI(Internet Server API)服务器扩展来扩展IIS(Internet Information Services)的功能。 #### 第14章 数据库编程 - **ODBC数据库编程**:解释了ODBC(开放数据库互联)的概念,并提供了使用ODBC API进行数据库访问的示例。 - **ADO编程**:介绍了ADO(ActiveX Data Objects)技术,讲解了如何使用ADO进行数据库的增删改查等操作。 #### 第15章 HTML帮助系统编程 - **创建HTML帮助文件**:讲解了如何创建HTML帮助文件(.chm),这是微软帮助系统的一种形式。 - **区分上下文帮助**:提供了在应用程序中实现上下文敏感帮助的技术示例。 #### 第16章 安装和部署项目 - **用安装程序向导创建安装项目**:介绍了如何使用Visual Studio中的安装和部署项目向导,快速创建安装程序。 - **部署应用程序**:阐述了部署应用程序到目标系统的过程,以及如何确保应用程序的正确安装和运行。 以上内容涵盖了Visual C++.NET编程技术体验一书中涉及的各个技术点,并对每个章节中的示例做了详细的说明。这些知识点对于理解和掌握Visual C++.NET编程非常重要,并能够帮助读者在实际项目开发中应用这些技术。
recommend-type

HarmonyOS内核深度探秘:优化自由行旅游系统的策略

# 1. HarmonyOS内核概述与旅游系统需求分析 ## 1.1 HarmonyOS内核概述 HarmonyOS(鸿蒙操作系统)是由华为开发的一个分布式操作系统,旨在提供跨多种设备的无缝体验。其内核设计理念强调高效、安全和模块化,以微内核架构和分布式能力
recommend-type

tkinter模块所有控件

<think>好的,我现在需要回答用户关于Tkinter模块中所有控件列表的问题。首先,我需要回忆Tkinter的基础知识,确保自己了解各个控件的名称和用途。用户希望得到所有支持的控件列表,所以必须全面覆盖,不能遗漏。 首先,我应该从Tkinter的标准控件开始。常见的控件包括Label、Button、Entry这些基础部件。然后是Frame,用于布局,还有Canvas用于绘图。接下来是Checkbutton、Radiobutton,这些属于选择类控件。Listbox和Scrollbar通常一起使用,处理滚动内容。还有Scale(滑块)、Spinbox、Menu、Menubutton这些可能
recommend-type

局域网五子棋游戏:娱乐与聊天的完美结合

标题“网络五子棋”和描述“适合于局域网之间娱乐和聊天!”以及标签“五子棋 网络”所涉及的知识点主要围绕着五子棋游戏的网络版本及其在局域网中的应用。以下是详细的知识点: 1. 五子棋游戏概述: 五子棋是一种两人对弈的纯策略型棋类游戏,又称为连珠、五子连线等。游戏的目标是在一个15x15的棋盘上,通过先后放置黑白棋子,使得任意一方先形成连续五个同色棋子的一方获胜。五子棋的规则简单,但策略丰富,适合各年龄段的玩家。 2. 网络五子棋的意义: 网络五子棋是指可以在互联网或局域网中连接进行对弈的五子棋游戏版本。通过网络版本,玩家不必在同一地点即可进行游戏,突破了空间限制,满足了现代人们快节奏生活的需求,同时也为玩家们提供了与不同对手切磋交流的机会。 3. 局域网通信原理: 局域网(Local Area Network,LAN)是一种覆盖较小范围如家庭、学校、实验室或单一建筑内的计算机网络。它通过有线或无线的方式连接网络内的设备,允许用户共享资源如打印机和文件,以及进行游戏和通信。局域网内的计算机之间可以通过网络协议进行通信。 4. 网络五子棋的工作方式: 在局域网中玩五子棋,通常需要一个客户端程序(如五子棋.exe)和一个服务器程序。客户端负责显示游戏界面、接受用户输入、发送落子请求给服务器,而服务器负责维护游戏状态、处理玩家的游戏逻辑和落子请求。当一方玩家落子时,客户端将该信息发送到服务器,服务器确认无误后将更新后的棋盘状态传回给所有客户端,更新显示。 5. 五子棋.exe程序: 五子棋.exe是一个可执行程序,它使得用户可以在个人计算机上安装并运行五子棋游戏。该程序可能包含了游戏的图形界面、人工智能算法(如果支持单机对战AI的话)、网络通信模块以及游戏规则的实现。 6. put.wav文件: put.wav是一个声音文件,很可能用于在游戏进行时提供声音反馈,比如落子声。在网络环境中,声音文件可能被用于提升玩家的游戏体验,尤其是在局域网多人游戏场景中。当玩家落子时,系统会播放.wav文件中的声音,为游戏增添互动性和趣味性。 7. 网络五子棋的技术要求: 为了确保多人在线游戏的顺利进行,网络五子棋需要具备一些基本的技术要求,包括但不限于稳定的网络连接、高效的数据传输协议(如TCP/IP)、以及安全的数据加密措施(如果需要的话)。此外,还需要有一个良好的用户界面设计来提供直观和舒适的用户体验。 8. 社交与娱乐: 网络五子棋除了是一个娱乐游戏外,它还具有社交功能。玩家可以通过游戏内的聊天系统进行交流,分享经验和策略,甚至通过网络寻找新的朋友。这使得网络五子棋不仅是一个个人娱乐工具,同时也是一种社交活动。 总结来说,网络五子棋结合了五子棋游戏的传统魅力和现代网络技术,使得不同地区的玩家能够在局域网内进行娱乐和聊天,既丰富了人们的娱乐生活,又加强了人际交流。而实现这一切的基础在于客户端程序的设计、服务器端的稳定运行、局域网的高效通信,以及音效文件增强的游戏体验。
recommend-type

自由行旅游新篇章:HarmonyOS技术融合与系统架构深度解析

# 1. HarmonyOS技术概述 ## 1.1 HarmonyOS的起源与发展 HarmonyOS(鸿蒙操作系统)由华为公司开发,旨在构建全场景分布式OS,以应对不同设备间的互联问题。自从2019年首次发布以来,HarmonyOS迅速成长,并迅速应用于智能手机、平板、智能穿戴、车载设备等多种平台。该系