活动介绍

python cv2.puttext 根据视频的长宽,在右上角,增加文字

时间: 2024-05-07 19:21:15 浏览: 119
可以使用OpenCV的putText函数在视频的右上角增加文字。首先需要获取视频的长宽,然后确定文字的位置,最后使用putText函数增加文字。 以下是一个示例代码: ```python import cv2 # 读取视频 cap = cv2.VideoCapture('video.mp4') # 获取视频的长宽 width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 定义文字内容和位置 text = 'Hello World!' org = (width - 200, 50) # 右上角 while True: ret, frame = cap.read() if ret: # 在视频帧上增加文字 cv2.putText(frame, text, org, cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) # 显示视频帧 cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break else: break # 释放资源 cap.release() cv2.destroyAllWindows() ``` 在上面的代码中,我们首先使用`cv2.VideoCapture`函数读取视频,然后使用`cap.get`函数获取视频的长宽。接着,我们定义了要显示的文字内容和位置,这里我们将文字显示在视频的右上角。在每一帧视频上,我们使用`cv2.putText`函数将文字增加到视频帧中。最后,我们使用`cv2.imshow`函数显示视频帧,并等待用户按下`q`键退出程序。
阅读全文

相关推荐

def plot_one_box(x, im, color=(128, 128, 128), label=None, line_thickness=3): """一般会用在detect.py中在nms之后变量每一个预测框,再将每个预测框画在原图上 使用opencv在原图im上画一个bounding box :params x: 预测得到的bounding box [x1 y1 x2 y2] :params im: 原图 要将bounding box画在这个图上 array :params color: bounding box线的颜色 :params labels: 标签上的框框信息 类别 + score :params line_thickness: bounding box的线宽 """ # check im内存是否连续 assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to plot_on_box() input image.' # tl = 框框的线宽 要么等于line_thickness要么根据原图im长宽信息自适应生成一个 tl = line_thickness or round(0.002 * (im.shape[0] + im.shape[1]) / 2) + 1 # line/font thickness # c1 = (x1, y1) = 矩形框的左上角 c2 = (x2, y2) = 矩形框的右下角 c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) # cv2.rectangle: 在im上画出框框 c1: start_point(x1, y1) c2: end_point(x2, y2) # 注意: 这里的c1+c2可以是左上角+右下角 也可以是左下角+右上角都可以 cv2.rectangle(im, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) # 如果label不为空还要在框框上面显示标签label + score if label: tf = max(tl - 1, 1) # label字体的线宽 font thickness # cv2.getTextSize: 根据输入的label信息计算文本字符串的宽度和高度 # 0: 文字字体类型 fontScale: 字体缩放系数 thickness: 字体笔画线宽 # 返回retval 字体的宽高 (width, height), baseLine 相对于最底端文本的 y 坐标 t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 # 同上面一样是个画框的步骤 但是线宽thickness=-1表示整个矩形都填充color颜色 cv2.rectangle(im, c1, c2, color, -1, cv2.LINE_AA) # filled # cv2.putText: 在图片上写文本 这里是在上面这个矩形框里写label + score文本 # (c1[0], c1[1] - 2)文本左下角坐标 0: 文字样式 fontScale: 字体缩放系数 # [225, 255, 255]: 文字颜色 thickness: tf字体笔画线宽 lineType: 线样式 cv2.putText(im, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)

import cv2 import numpy as np from PIL import Image # 参数配置(根据实际情况调整) BLUR_KERNEL_SIZE = (5, 5) # 高斯模糊核大小 MIN_AREA = 50 # 最小坑洞面积阈值 MAX_AREA = 1000 # 最大坑洞面积阈值 FONT_SCALE = 0.7 # 标注字体大小 FONT_COLOR = (255, 0, 0) # 标注颜色 (BGR格式) CONTOUR_COLOR = (0, 255, 0) # 轮廓颜色 (BGR格式) # 读取TIFF图像 image_path = "input.tif" image_pil = Image.open(image_path) image_np = np.array(image_pil) # 转换为灰度图像 if len(image_np.shape) == 3: gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY) else: gray = image_np.copy() # 图像预处理 blurred = cv2.GaussianBlur(gray, BLUR_KERNEL_SIZE, 0) # 自适应阈值处理 thresh = cv2.adaptiveThreshold( blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # 形态学操作(去除小噪点) kernel = np.ones((3, 3), np.uint8) cleaned = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 查找轮廓 contours, _ = cv2.findContours(cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 过滤轮廓 filtered_contours = [] for cnt in contours: area = cv2.contourArea(cnt) if MIN_AREA < area < MAX_AREA: filtered_contours.append(cnt) # 创建标注图像 output_image = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) if len(image_np.shape) == 2 else image_np.copy() # 绘制轮廓和标注 for i, cnt in enumerate(filtered_contours): # 计算最小外接圆 (x, y), radius = cv2.minEnclosingCircle(cnt) center = (int(x), int(y)) # center是元组,例如 (100, 200) # 绘制圆形轮廓 cv2.circle(output_image, center, int(radius), CONTOUR_COLOR, 2) # 修正坐标:分别对x和y坐标减10(原错误是直接操作元组) text_position = (center[0] - 10, center[1] - 10) # 添加数字标注 cv2.putText(output_image, str(i + 1), text_position, # 使用修正后的坐标 cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR, 2) # 保存结果 output_image_pil = Image.fromarray(cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB)) output_image_pil.save('output.tif') # 显示结果 print(f"检测到的小坑数量: {len(filtered_contours)}") 它把一些不是坑的、条型的 也识别成了小坑 怎么修改

import cv2 import numpy as np import torch import argparse from pathlib import Path from yolov5.models.experimental import attempt_load from yolov5.utils.general import non_max_suppression def detect_crosswalk(image): """检测斑马线区域并返回中心线x坐标""" hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) lower_white = np.array([0, 0, 200]) upper_white = np.array([180, 30, 255]) mask = cv2.inRange(hsv, lower_white, upper_white) kernel = np.ones((10, 10), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2) cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours = cnts[0] if len(cnts) == 2 else cnts[1] max_area = 0 crosswalk_rect = None for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) aspect_ratio = w / h area = w * h if aspect_ratio > 2 and area > 5000: if area > max_area: max_area = area crosswalk_rect = (x, y, w, h) # 存储完整坐标信息 # 修正后的返回逻辑 if crosswalk_rect: x, _, w, _ = crosswalk_rect # 从存储的元组中解包 return x + w // 2 else: return image.shape[1] // 2 def process_frame(frame, model, device): """处理单帧的核心逻辑""" # YOLOv5检测 img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img_tensor = torch.from_numpy(img_rgb).permute(2, 0, 1).float().div(255) img_tensor = img_tensor.unsqueeze(0).to(device) with torch.no_grad(): pred = model(img_tensor)[0] pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45) # 斑马线检测 center_x = detect_crosswalk(frame) cv2.line(frame, (center_x, 0), (center_x, frame.shape[0]), (0, 255, 255), 2) # 处理检测结果 if pred and pred[0] is not None: for det in pred[0]: x1, y1, x2, y2, conf, cls = det.cpu().numpy() if int(cls) not in [0, 2, 5, 7]: continue x1, y1, x2, y2 = map(int, [x1, y1, x2, y2]) obj_center = (x1 + x2) // 2 position = "左侧" if obj_center < center_x else "右侧" color = (0, 255, 0) if position == "左侧" else (0, 0, 255) cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2) cv2.putText(frame, f'{position}', (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) return frame def main(input_path='test.jpg'): # 设备初始化 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 加载模型 model_path = Path('yolov5s.pt') if not model_path.exists(): raise FileNotFoundError(f"Model file {model_path} not found") model = attempt_load(model_path).to(device) # 视频处理模式 if input_path.isdigit() or Path(input_path).suffix in ['.mp4', '.avi']: cap = cv2.VideoCapture(int(input_path) if input_path.isdigit() else input_path) while cap.isOpened(): ret, frame = cap.read() if not ret: break processed = process_frame(frame, model, device) cv2.imshow('Detection', processed) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() # 图片处理模式 else: frame = cv2.imread(input_path) if frame is None: raise ValueError(f"Cannot read image from {input_path}") processed = process_frame(frame, model, device) cv2.imshow('Result', processed) cv2.waitKey(0) cv2.destroyAllWindows() if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--input', type=str, default='test.jpg', help='输入路径 (图片/视频/摄像头ID)') args = parser.parse_args() main(args.input) 以上是我写的一段代码,请你分析这段代码有什么作用并进行改进

import cv2 import numpy as np import openpyxl from openpyxl.utils import get_column_letter def process_image(image, wb, sheet, frame_count, scale_percent=0.35): try: # 图像预处理 height, width = image.shape[:2] new_width = int(width * scale_percent) new_height = int(height * scale_percent) resized = cv2.resize(image, (new_width, new_height), cv2.INTER_AREA) # HSV颜色空间转换 hsv = cv2.cvtColor(resized, cv2.COLOR_BGR2HSV) # 改进的红色检测范围 lower_red1 = np.array([0, 100, 75]) # 提高饱和度下限 upper_red1 = np.array([8, 255, 255]) lower_red2 = np.array([135, 120, 75]) # 缩小第二个范围 upper_red2 = np.array([160, 255, 255]) # 创建优化掩膜 mask1 = cv2.inRange(hsv, lower_red1, upper_red1) mask2 = cv2.inRange(hsv, lower_red2, upper_red2) mask = cv2.bitwise_or(mask1, mask2) # 改进的形态学操作 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1) # 轮廓检测优化 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: # 筛选有效轮廓(面积>100) valid_contours = [c for c in contours if cv2.contourArea(c) > 100] if not valid_contours: return max_contour = max(valid_contours, key=cv2.contourArea) # 精确质心计算 M = cv2.moments(max_contour) if M["m00"] != 0: center_x = int(M["m10"] / M["m00"]) center_y = int(M["m01"] / M["m00"]) else: x, y, w, h = cv2.boundingRect(max_contour) center_x = x + w // 2 center_y = y + h // 2 # 亚像素级优化 gray_mask = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01) corners = cv2.goodFeaturesToTrack(gray_mask, 1, 0.01, 10) if corners is not None: corners = cv2.cornerSubPix(gray_mask, corners, (3, 3), (-1, -1), criteria) center_x, center_y = int(corners[0][0][0]), int(corners[0][0][1]) # 数据记录 sheet.cell(row=frame_count + 2, column=1).value = frame_count sheet.cell(row=frame_count + 2, column=2).value = center_x sheet.cell(row=frame_count + 2, column=3).value = center_y # 可视化增强 cv2.drawContours(resized, [max_contour], -1, (0, 255, 0), 2) cv2.circle(resized, (center_x, center_y), 5, (0, 0, 255), -1) cv2.putText(resized, f"({center_x}, {center_y})", (center_x + 10, center_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) cv2.imshow('Precision Tracking', resized) cv2.waitKey(1) except Exception as e: print(f"Frame {frame_count} error: {str(e)}") def process_video(video_path, scale_percent=0.35): cap = cv2.VideoCapture(video_path) frame_count = 0 # 创建Excel文件并优化列宽 wb = openpyxl.Workbook() sheet = wb.active sheet.title = "Precision Tracking" headers = ["Frame", "Center X", "Center Y"] for col, header in enumerate(headers, 1): sheet.cell(row=1, column=col).value = header sheet.column_dimensions[get_column_letter(col)].width = 15 while cap.isOpened(): ret, frame = cap.read() if not ret: break process_image(frame, wb, sheet, frame_count, scale_percent) frame_count += 1 if frame_count % 50 == 0: print(f"Processed {frame_count} frames") # 保存优化 wb.save("precision_coordinates.xlsx") cap.release() cv2.destroyAllWindows() print(f"Total processed frames: {frame_count}") # 使用示例 if __name__ == "__main__": video_path = "1-4.mp4" process_video(video_path)请完善该代码,使其捕捉的是红色区域点的坐标

import cv2 import numpy as np import torch import time import os from utils.general import non_max_suppression, scale_boxes if __name__ == "__main__": device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # 检测是否有gpu,有则使用gpu weights = 'xw_xk_2_21.pt' w = str(weights) # 将权重地址转换为字符串 model = torch.load(w, map_location=device)['model'].float().fuse().eval() # 加载模型,float()转换为float32,fuse()融合模型加速推理,eval()评估模式 video_path = '20250319-110523.mp4' # 输入视频路径 output_video_path = '/root/autodl-tmp/xw_xk_2_20/videos/output/output_processed.mp4' # 输出视频路径 # 确保输出目录存在 output_dir = os.path.dirname(output_video_path) if not os.path.exists(output_dir): os.makedirs(output_dir) cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"Error opening video file {video_path}") exit(-1) # 获取视频属性 fps = cap.get(cv2.CAP_PROP_FPS) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 创建 VideoWriter 对象 out = cv2.VideoWriter(output_video_path, fourcc, fps, (width, height)) while True: ret, frame = cap.read() if not ret: break img0 = frame.copy() start = time.time() ############################### 动态调整图片大小 ############################################## height, width = img0.shape[:2] # 比较宽和高大小,将最大的设为640 if height > width: target = 640 scale = target / height # 计算缩放后的尺寸,高度向下取整至32的倍数 new_width = int(width * scale / 32) * 32 new_height = target else: target = 640 scale = target / width # 计算缩放后的尺寸,高度向下取整至32的倍数 new_height = int(height * scale / 32) * 32 new_width = target # 缩放图像 img = cv2.resize(img0, (new_width, new_height)) ############################################################################################ img = img / 255. # 归一化至 [0,1] img = img[:, :, ::-1].transpose((2, 0, 1)) # HWC 转 CHW img = np.expand_dims(img, axis=0) # 扩展维度至 [1,3,new_height,new_width] img = torch.from_numpy(img.copy()) # numpy 转 tensor img = img.to(torch.float32) # float64 转换 float32 img = img.to(device) # cpu 转 gpu pred = model(img) pred = non_max_suppression(pred, 0.25, 0.45, None, False, max_det=1000) # 非极大值抑制, 去除重复框 first_box_drawn = False n = 0 for i, det in enumerate(pred): if len(det): det[:, :4] = scale_boxes(img.shape[2:], det[:, :4], img0.shape).round() # 将预测框缩放至原图尺寸 end = time.time() print("ms ", (end - start) * 1000) for *xyxy, conf, cls in reversed(det): x1, y1, x2, y2 = int(xyxy[0]), int(xyxy[1]), int(xyxy[2]), int(xyxy[3]) if not first_box_drawn: # 涂黑第一个检测到的目标 cv2.rectangle(img0, (x1, y1), (x2, y2), (0, 0, 0), -1) # 涂黑 first_box_drawn = True else: # 绘制其他检测框和标签 cv2.rectangle(img0, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img0, f'{int(cls)} {conf:.2f}', (x1, y1), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) print(x1, y1, x2, y2, float(conf), int(cls)) n += 1 # 写入处理后的帧 out.write(img0) cap.release() out.release() print(f"Processed video saved to {output_video_path}") 帮我看一下代码逻辑

CONF_THRESH = 0.5 IOU_THRESHOLD = 0.4 POSE_NUM = 17 * 3 DET_NUM = 6 SEG_NUM = 32 OBB_NUM = 1 def get_img_path_batches(batch_size, img_dir): ret = [] batch = [] for root, dirs, files in os.walk(img_dir): for name in files: if len(batch) == batch_size: ret.append(batch) batch = [] batch.append(os.path.join(root, name)) if len(batch) > 0: ret.append(batch) return ret def plot_one_box(x, img, color=None, label=None, line_thickness=None): """ description: Plots one bounding box on image img, this function comes from YoLov8 project. param: x: a box likes [x1,y1,x2,y2] img: a opencv image object color: color to draw rectangle, such as (0,255,0) label: str line_thickness: int return: no return """ tl = ( line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 ) # line/font thickness color = color or [random.randint(0, 255) for _ in range(3)] c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) if label: tf = max(tl - 1, 1) # font thickness t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled cv2.putText( img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA, ) class YoLov8TRT(object): """ description: A YOLOv8 class that warps TensorRT ops, preprocess and postprocess ops. """ def __init__(self, engine_file_path): # Create a Context on this device, self.ctx = cuda.Device(0).make_context() stream = cuda.Stream() TRT_LOGGER = trt.Logger(trt.Logger.INFO) runtime = trt.Runtime(TRT_LOGGER) # Deserialize the engine from file with open(engine_file_path, "rb") as f: engine = runtime.deserialize_cuda_engine(f.read()) context = engine.create_execution_context() host_inputs = [] cuda_inputs = [] host_outputs = [] cuda_outputs = [] bindings = [] for binding in engine: print('bingding:', binding, engine.get_binding_shape(binding)) size = trt.volume(engine.get_binding_shape(binding)) * engine.max_batch_size dtype = trt.nptype(engine.get_binding_dtype(binding)) # Allocate host and device buffers host_mem = cuda.pagelocked_empty(size, dtype) cuda_mem = cuda.mem_alloc(host_mem.nbytes) # Append the device buffer to device bindings. bindings.append(int(cuda_mem)) # Append to the appropriate list. if engine.binding_is_input(binding): self.input_w = engine.get_binding_shape(binding)[-1] self.input_h = engine.get_binding_shape(binding)[-2] host_inputs.append(host_mem) cuda_inputs.append(cuda_mem) else: host_outputs.append(host_mem) cuda_outputs.append(cuda_mem) # Store self.stream = stream self.context = context self.engine = engine self.host_inputs = host_inputs self.cuda_inputs = cuda_inputs self.host_outputs = host_outputs self.cuda_outputs = cuda_outputs self.bindings = bindings self.batch_size = engine.max_batch_size self.det_output_length = host_outputs[0].shape[0] def infer(self, raw_image_generator): threading.Thread.__init__(self) # Make self the active context, pushing it on top of the context stack. self.ctx.push() # Restore stream = self.stream context = self.context host_inputs = self.host_inputs cuda_inputs = self.cuda_inputs host_outputs = self.host_outputs cuda_outputs = self.cuda_outputs bindings = self.bindings # Do image preprocess batch_image_raw = [] batch_origin_h = [] batch_origin_w = [] batch_input_image = np.empty(shape=[self.batch_size, 3, self.input_h, self.input_w]) for i, image_raw in enumerate(raw_image_generator): input_image, image_raw, origin_h, origin_w = self.preprocess_image(image_raw) batch_image_raw.append(image_raw) batch_origin_h.append(origin_h) batch_origin_w.append(origin_w) np.copyto(batch_input_image[i], input_image) batch_input_image = np.ascontiguousarray(batch_input_image) # Copy input image to host buffer np.copyto(host_inputs[0], batch_input_image.ravel()) start = time.time() # Transfer input data to the GPU. cuda.memcpy_htod_async(cuda_inputs[0], host_inputs[0], stream) # Run inference. context.execute_async(batch_size=self.batch_size, bindings=bindings, stream_handle=stream.handle) # Transfer predictions back from the GPU. cuda.memcpy_dtoh_async(host_outputs[0], cuda_outputs[0], stream) # Synchronize the stream stream.synchronize() end = time.time() # Remove any context from the top of the context stack, deactivating it. self.ctx.pop() # Here we use the first row of output in that batch_size = 1 output = host_outputs[0] # Do postprocess for i in range(self.batch_size): result_boxes, result_scores, result_classid = self.post_process( output[i * self.det_output_length: (i + 1) * self.det_output_length], batch_origin_h[i], batch_origin_w[i] ) # Draw rectangles and labels on the original image for j in range(len(result_boxes)): box = result_boxes[j] plot_one_box( box, batch_image_raw[i], label="{}:{:.2f}".format( categories[int(result_classid[j])], result_scores[j] ), ) return batch_image_raw, end - start def destroy(self): # Remove any context from the top of the context stack, deactivating it. self.ctx.pop() def get_raw_image(self, image_path_batch): """ description: Read an image from image path """ for img_path in image_path_batch: yield cv2.imread(img_path) def get_raw_image_zeros(self, image_path_batch=None): """ description: Ready data for warmup """ for _ in range(self.batch_size): yield np.zeros([self.input_h, self.input_w, 3], dtype=np.uint8) def preprocess_image(self, raw_bgr_image): """ description: Convert BGR image to RGB, resize and pad it to target size, normalize to [0,1], transform to NCHW format. param: input_image_path: str, image path return: image: the processed image image_raw: the original image h: original height w: original width """

import cv2 import numpy as np import os def process_image(img_path): """处理单张图片并返回最长边和最短边的像素长度""" img = cv2.imread(img_path) if img is None: print(f'错误: 无法读取图片 {img_path}') return None, None # 图像处理流程 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_filtering = cv2.medianBlur(img_gray, 3) _, img_threshold = cv2.threshold(img_filtering, 150, 255, cv2.THRESH_BINARY) kernel = np.ones((5, 5), np.uint8) opening = cv2.morphologyEx(img_threshold, cv2.MORPH_OPEN, kernel) closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel) edge_img = cv2.Canny(closing, 32, 128, True) contours, _ = cv2.findContours(edge_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: print(f'警告: 未检测到轮廓 {img_path}') return None, None # 选择面积最大的轮廓 cnt = max(contours, key=cv2.contourArea) rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) # 计算四条边长度并找出最长和最短边 edges = [ np.linalg.norm(box[0] - box[1]), np.linalg.norm(box[1] - box[2]), np.linalg.norm(box[2] - box[3]), np.linalg.norm(box[3] - box[0]) ] return max(edges), min(edges) def batch_process_images(input_folder, output_txt, pixel_scale=1.0): """ 批量处理文件夹中的所有图片并保存结果 :param input_folder: 图片文件夹路径 :param output_txt: 输出文件路径 :param pixel_scale: 像素比例系数(将像素长度转换为实际长度) """ valid_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.tiff') results = [] for filename in os.listdir(input_folder): if filename.lower().endswith(valid_extensions): img_path = os.path.join(input_folder, filename) longest_px, shortest_px = process_image(img_path) if longest_px is not None and shortest_px is not None: # 应用像素比例系数 longest_actual = longest_px * pixel_scale shortest_actual = shortest_px * pixel_scale results.append((filename, longest_px, shortest_px, longest_actual, shortest_actual)) print(f"已处理: {filename} | 最长边(px): {longest_px:.2f} | 最短边(px): {shortest_px:.2f}") print(f"已处理: {filename} | 最长边: {longest_actual:.2f} | 最短边(px): {shortest_actual:.2f}") # 保存结果到文本文件 with open(output_txt, 'w') as f: f.write("图片名称\t原始最长边(像素)\t原始最短边(像素)\t转换后最长边\t转换后最短边\n") for filename, longest_px, shortest_px, longest_actual, shortest_actual in results: f.write(f"{filename}\t{longest_px:.2f}\t{shortest_px:.2f}\t{longest_actual:.4f}\t{shortest_actual:.4f}\n") print(f"\n处理完成! 共处理 {len(results)} 张图片") print(f"像素比例系数: {pixel_scale}") print(f"结果已保存至: {output_txt}") # 使用示例 if __name__ == "__main__": input_folder = "E:/CCD/TG" # 图片文件夹路径 output_txt = "E:/CCD/TG/converted_results.txt" # 输出文件路径 # 设置像素比例系数(例如:0.1表示1像素=3.94微米) pixel_scale = 3.94 # 根据实际情况调整此值 batch_process_images(input_folder, output_txt, pixel_scale) 根据以上代码,不需要再保存最长边与最短边的结果,而是编写一个后续代码,使得可以利用转换像素后的实际最长边与最短边,以最长边为高,最短边为底面直径,按照圆柱体体积计算公式计算对应的体积,再根据给定的密度1,计算相对应的重量,在根据给定的体积计算生物量。最终生成一个运行脚本

最新推荐

recommend-type

C# Socket通信源码:多连接支持与断线重连功能的物联网解决方案

内容概要:本文介绍了一套基于C#编写的Socket服务器与客户端通信源码,源自商业级物联网项目。这套代码实现了双Socket机制、多连接支持以及断线重连功能,适用于各类C#项目(如MVC、Winform、控制台、Webform)。它通过简单的静态类调用即可获取客户端传输的数据,并内置了接收和发送数据缓冲队列,确保数据传输的稳定性。此外,代码提供了数据读取接口,但不涉及具体的数据处理逻辑。文中详细展示了服务端和客户端的基本配置与使用方法,强调了在实际应用中需要注意的问题,如避免主线程执行耗时操作以防内存膨胀。 适合人群:具备基本C#编程能力的研发人员,尤其是对Socket通信有一定了解并希望快速集成相关功能到现有项目中的开发者。 使用场景及目标:① 需要在短时间内为C#项目增加稳定的Socket通信功能;② 实现多设备间的数据交换,特别是对于智能家居、工业传感器等物联网应用场景。 其他说明:虽然该代码能够满足大多数中小型项目的通信需求,但对于需要高性能、低延迟的金融级交易系统则不太合适。同时,代码并未采用异步技术,因此在面对海量连接时可能需要进一步优化。
recommend-type

掌握XFireSpring整合技术:HELLOworld原代码使用教程

标题:“xfirespring整合使用原代码”中提到的“xfirespring”是指将XFire和Spring框架进行整合使用。XFire是一个基于SOAP的Web服务框架,而Spring是一个轻量级的Java/Java EE全功能栈的应用程序框架。在Web服务开发中,将XFire与Spring整合能够发挥两者的优势,例如Spring的依赖注入、事务管理等特性,与XFire的简洁的Web服务开发模型相结合。 描述:“xfirespring整合使用HELLOworld原代码”说明了在这个整合过程中实现了一个非常基本的Web服务示例,即“HELLOworld”。这通常意味着创建了一个能够返回"HELLO world"字符串作为响应的Web服务方法。这个简单的例子用来展示如何设置环境、编写服务类、定义Web服务接口以及部署和测试整合后的应用程序。 标签:“xfirespring”表明文档、代码示例或者讨论集中于XFire和Spring的整合技术。 文件列表中的“index.jsp”通常是一个Web应用程序的入口点,它可能用于提供一个用户界面,通过这个界面调用Web服务或者展示Web服务的调用结果。“WEB-INF”是Java Web应用中的一个特殊目录,它存放了应用服务器加载的Servlet类文件和相关的配置文件,例如web.xml。web.xml文件中定义了Web应用程序的配置信息,如Servlet映射、初始化参数、安全约束等。“META-INF”目录包含了元数据信息,这些信息通常由部署工具使用,用于描述应用的元数据,如manifest文件,它记录了归档文件中的包信息以及相关的依赖关系。 整合XFire和Spring框架,具体知识点可以分为以下几个部分: 1. XFire框架概述 XFire是一个开源的Web服务框架,它是基于SOAP协议的,提供了一种简化的方式来创建、部署和调用Web服务。XFire支持多种数据绑定,包括XML、JSON和Java数据对象等。开发人员可以使用注解或者基于XML的配置来定义服务接口和服务实现。 2. Spring框架概述 Spring是一个全面的企业应用开发框架,它提供了丰富的功能,包括但不限于依赖注入、面向切面编程(AOP)、数据访问/集成、消息传递、事务管理等。Spring的核心特性是依赖注入,通过依赖注入能够将应用程序的组件解耦合,从而提高应用程序的灵活性和可测试性。 3. XFire和Spring整合的目的 整合这两个框架的目的是为了利用各自的优势。XFire可以用来创建Web服务,而Spring可以管理这些Web服务的生命周期,提供企业级服务,如事务管理、安全性、数据访问等。整合后,开发者可以享受Spring的依赖注入、事务管理等企业级功能,同时利用XFire的简洁的Web服务开发模型。 4. XFire与Spring整合的基本步骤 整合的基本步骤可能包括添加必要的依赖到项目中,配置Spring的applicationContext.xml,以包括XFire特定的bean配置。比如,需要配置XFire的ServiceExporter和ServicePublisher beans,使得Spring可以管理XFire的Web服务。同时,需要定义服务接口以及服务实现类,并通过注解或者XML配置将其关联起来。 5. Web服务实现示例:“HELLOworld” 实现一个Web服务通常涉及到定义服务接口和服务实现类。服务接口定义了服务的方法,而服务实现类则提供了这些方法的具体实现。在XFire和Spring整合的上下文中,“HELLOworld”示例可能包含一个接口定义,比如`HelloWorldService`,和一个实现类`HelloWorldServiceImpl`,该类有一个`sayHello`方法返回"HELLO world"字符串。 6. 部署和测试 部署Web服务时,需要将应用程序打包成WAR文件,并部署到支持Servlet 2.3及以上版本的Web应用服务器上。部署后,可以通过客户端或浏览器测试Web服务的功能,例如通过访问XFire提供的服务描述页面(WSDL)来了解如何调用服务。 7. JSP与Web服务交互 如果在应用程序中使用了JSP页面,那么JSP可以用来作为用户与Web服务交互的界面。例如,JSP可以包含JavaScript代码来发送异步的AJAX请求到Web服务,并展示返回的结果给用户。在这个过程中,JSP页面可能使用XMLHttpRequest对象或者现代的Fetch API与Web服务进行通信。 8. 项目配置文件说明 项目配置文件如web.xml和applicationContext.xml分别在Web应用和服务配置中扮演关键角色。web.xml负责定义Web组件,比如Servlet、过滤器和监听器,而applicationContext.xml则负责定义Spring容器中的bean,包括数据源、事务管理器、业务逻辑组件和服务访问器等。 总之,通过上述整合使用原代码的知识点,可以深入理解XFire与Spring框架的结合使用,以及如何开发和部署基本的Web服务。这些技术知识有助于进行更高层次的Web服务开发,以及在复杂的IT环境中灵活运用各种框架和工具。
recommend-type

【Unity2018汉化大揭秘】:一步到位优化中文用户体验

# 摘要 本论文详细介绍了Unity2018汉化项目的实施过程,从理论准备到实践步骤,再到后期的测试与优化,最终分享了汉化经验和心得。首先,强调了汉化项目对于用户体验提升和产品国际化的重要性,并分析了汉化资源的分类、识别与管理方法。接着,详细阐述了汉化工具的选择、脚本编写、资源手动调整等实践步骤,以及汉化质量测试、体验优化和项目维护更新的重要性。论文最后通过案例研究,分析了汉化中的挑战和应对策略,并预测了汉化技术未来的发展方向。整个汉化过程不仅涉及技术层面的操作,还包含了深入的理论研究和实践心得分享,对提升汉化项目的效率和质量具有指导意义。 # 关键字 Unity汉化;用户体验;国际化;资源
recommend-type

iPhone

<think>我们注意到用户意图不明确,但提到了“照片提取”和“其他功能帮助”。因此,我们需要通过搜索来获取关于iPhone照片提取的常见方法以及其他可能的功能帮助。由于用户问题比较宽泛,我们将重点放在照片提取上,因为这是明确提到的关键词。同时,我们也会考虑一些其他常用功能的帮助。首先,针对照片提取,可能涉及从iPhone导出照片、从备份中提取照片、或者从损坏的设备中恢复照片等。我们将搜索这些方面的信息。其次,关于其他功能帮助,我们可以提供一些常见问题的快速指南,如电池优化、屏幕时间管理等。根据要求,我们需要将答案组织为多个方法或步骤,并在每个步骤间换行。同时,避免使用第一人称和步骤词汇。由于
recommend-type

驾校一点通软件:提升驾驶证考试通过率

标题“驾校一点通”指向的是一款专门为学员考取驾驶证提供帮助的软件,该软件强调其辅助性质,旨在为学员提供便捷的学习方式和复习资料。从描述中可以推断出,“驾校一点通”是一个与驾驶考试相关的应用软件,这类软件一般包含驾驶理论学习、模拟考试、交通法规解释等内容。 文件标题中的“2007”这个年份标签很可能意味着软件的最初发布时间或版本更新年份,这说明了软件具有一定的历史背景和可能经过了多次更新,以适应不断变化的驾驶考试要求。 压缩包子文件的文件名称列表中,有以下几个文件类型值得关注: 1. images.dat:这个文件名表明,这是一个包含图像数据的文件,很可能包含了用于软件界面展示的图片,如各种标志、道路场景等图形。在驾照学习软件中,这类图片通常用于帮助用户认识和记忆不同交通标志、信号灯以及驾驶过程中需要注意的各种道路情况。 2. library.dat:这个文件名暗示它是一个包含了大量信息的库文件,可能包含了法规、驾驶知识、考试题库等数据。这类文件是提供给用户学习驾驶理论知识和准备科目一理论考试的重要资源。 3. 驾校一点通小型汽车专用.exe:这是一个可执行文件,是软件的主要安装程序。根据标题推测,这款软件主要是针对小型汽车驾照考试的学员设计的。通常,小型汽车(C1类驾照)需要学习包括车辆构造、基础驾驶技能、安全行车常识、交通法规等内容。 4. 使用说明.html:这个文件是软件使用说明的文档,通常以网页格式存在,用户可以通过浏览器阅读。使用说明应该会详细介绍软件的安装流程、功能介绍、如何使用软件的各种模块以及如何通过软件来帮助自己更好地准备考试。 综合以上信息,我们可以挖掘出以下几个相关知识点: - 软件类型:辅助学习软件,专门针对驾驶考试设计。 - 应用领域:主要用于帮助驾考学员准备理论和实践考试。 - 文件类型:包括图片文件(images.dat)、库文件(library.dat)、可执行文件(.exe)和网页格式的说明文件(.html)。 - 功能内容:可能包含交通法规知识学习、交通标志识别、驾驶理论学习、模拟考试、考试题库练习等功能。 - 版本信息:软件很可能最早发布于2007年,后续可能有多个版本更新。 - 用户群体:主要面向小型汽车驾照考生,即C1类驾照学员。 - 使用方式:用户需要将.exe安装文件进行安装,然后根据.html格式的使用说明来熟悉软件操作,从而利用images.dat和library.dat中的资源来辅助学习。 以上知识点为从给定文件信息中提炼出来的重点,这些内容对于了解“驾校一点通”这款软件的功能、作用、使用方法以及它的发展历史都有重要的指导意义。
recommend-type

【DFLauncher自动化教程】:简化游戏启动流程,让游戏体验更流畅

# 摘要 DFLauncher是一个功能丰富的游戏启动和管理平台,本论文将介绍其安装、基础使用、高级设置、社区互动以及插件开发等方面。通过对配置文件的解析、界面定制、自动化功能的实现、高级配置选项、安全性和性能监控的详细讨论,本文阐述了DFLauncher如何帮助用户更高效地管理和优化游戏环境。此外,本文还探讨了DFLauncher社区的资源分享、教育教程和插件开发等内容,
recommend-type

自适应卡尔曼滤波是什么意思

<think>嗯,用户这次想深入了解自适应卡尔曼滤波(AKF)的概念和原理。从对话历史看,用户之前研究过相机自动对焦系统的降噪技术,其中提到过自适应卡尔曼滤波的应用场景。用户可能是个工程师或研究者,正在探索信号处理在具体场景的实现细节。 用户提供的三篇参考文献很有价值:[1]是基础理论综述,[2]聚焦多传感器场景,[3]讨论噪声协方差自适应方法。需要特别注意相机AF系统的特殊需求——实时性要求高(每秒数十次对焦计算)、噪声环境复杂(机械振动/弱光干扰),这些在解释原理时要结合具体案例。 技术要点需要分层解析:先明确标准卡尔曼滤波的局限(固定噪声参数),再展开自适应机制。对于相机AF场景,重
recommend-type

EIA-CEA 861B标准深入解析:时间与EDID技术

EIA-CEA 861B标准是美国电子工业联盟(Electronic Industries Alliance, EIA)和消费电子协会(Consumer Electronics Association, CEA)联合制定的一个技术规范,该规范详细规定了视频显示设备和系统之间的通信协议,特别是关于视频显示设备的时间信息(timing)和扩展显示识别数据(Extended Display Identification Data,简称EDID)的结构与内容。 在视频显示技术领域,确保不同品牌、不同型号的显示设备之间能够正确交换信息是至关重要的,而这正是EIA-CEA 861B标准所解决的问题。它为制造商提供了一个统一的标准,以便设备能够互相识别和兼容。该标准对于确保设备能够正确配置分辨率、刷新率等参数至关重要。 ### 知识点详解 #### EIA-CEA 861B标准的历史和重要性 EIA-CEA 861B标准是随着数字视频接口(Digital Visual Interface,DVI)和后来的高带宽数字内容保护(High-bandwidth Digital Content Protection,HDCP)等技术的发展而出现的。该标准之所以重要,是因为它定义了电视、显示器和其他显示设备之间如何交互时间参数和显示能力信息。这有助于避免兼容性问题,并确保消费者能有较好的体验。 #### Timing信息 Timing信息指的是关于视频信号时序的信息,包括分辨率、水平频率、垂直频率、像素时钟频率等。这些参数决定了视频信号的同步性和刷新率。正确配置这些参数对于视频播放的稳定性和清晰度至关重要。EIA-CEA 861B标准规定了多种推荐的视频模式(如VESA标准模式)和特定的时序信息格式,使得设备制造商可以参照这些标准来设计产品。 #### EDID EDID是显示设备向计算机或其他视频源发送的数据结构,包含了关于显示设备能力的信息,如制造商、型号、支持的分辨率列表、支持的视频格式、屏幕尺寸等。这种信息交流机制允许视频源设备能够“了解”连接的显示设备,并自动设置最佳的输出分辨率和刷新率,实现即插即用(plug and play)功能。 EDID的结构包含了一系列的块(block),其中定义了包括基本显示参数、色彩特性、名称和序列号等在内的信息。该标准确保了这些信息能以一种标准的方式被传输和解释,从而简化了显示设置的过程。 #### EIA-CEA 861B标准的应用 EIA-CEA 861B标准不仅适用于DVI接口,还适用于HDMI(High-Definition Multimedia Interface)和DisplayPort等数字视频接口。这些接口技术都必须遵循EDID的通信协议,以保证设备间正确交换信息。由于标准的广泛采用,它已经成为现代视频信号传输和显示设备设计的基础。 #### EIA-CEA 861B标准的更新 随着技术的进步,EIA-CEA 861B标准也在不断地更新和修订。例如,随着4K分辨率和更高刷新率的显示技术的发展,该标准已经扩展以包括支持这些新技术的时序和EDID信息。任何显示设备制造商在设计新产品时,都必须考虑最新的EIA-CEA 861B标准,以确保兼容性。 #### 结论 EIA-CEA 861B标准是电子显示领域的一个重要规范,它详细定义了视频显示设备在通信时所使用的信号时序和设备信息的格式。该标准的存在,使得不同厂商生产的显示设备可以无缝连接和集成,极大地增强了用户体验。对于IT专业人士而言,了解和遵守EIA-CEA 861B标准是进行视频系统设计、故障诊断及设备兼容性测试的重要基础。
recommend-type

【DFLauncher应用实战】:如何将DFLauncher融入矮人要塞并提升效率

# 摘要 DFLauncher是一款功能全面的游戏管理工具,旨在简化游戏安装、启动和维护过程。本文介绍了DFLauncher的基本使用方法,详细解析了其核心功能,包括游戏库管理、游戏配置优化、更新机制等。同时,文章探讨了DFLauncher在特定游戏“矮人要塞”中的集成应用,以及通过插件和脚本进行的高级定制。故障诊断与系统优化章节提供了实用的诊断方法和性能提升技巧。最后,本文展望了DFLauncher的未来发展方向,并鼓励社区贡献和用户反馈,以满足不断变化的用户需求。 # 关键字 DFLauncher;游戏管理工具;安装配置;性能优化;故障诊断;社区贡献;定制化扩展;网络功能集成 参考资源
recommend-type

银河麒麟系统打开屏保

<think>嗯,用户的问题是关于银河麒麟操作系统如何开启屏幕保护程序。这个问题其实挺实用的,毕竟长时间盯着电脑屏幕容易造成视觉疲劳,屏幕保护能起到一定的保护作用。 从用户提供的引用内容来看,引用[2]提到了银河麒麟系统的常见问题处理,包括重启输入法和双屏配置问题,虽然不直接相关,但说明用户对系统设置有一定了解。引用[3]是关于安装cmake的,可能用户之前尝试过其他系统配置操作。 用户可能是在办公环境中使用银河麒麟系统,需要保护视力。考虑到银河麒麟是基于Linux开发的国产操作系统,它的屏幕保护设置应该和主流Linux发行版类似,但可能有自己的特色功能。 我回忆了一下Linux系统的屏