Python CV2图像鼠标选择任意区域截图

Python CV2实现鼠标选择任意区域截图

  • 前言
  • 实现流程
  • 结果分析
  • 附件

前言

网上Opencv实现此功能的资源较多,但是想用python实现却没有相关资源,所以自己参考其他C++程序实现了这个功能。但中间还有一些问题需要改进,由于时间问题,只是简单实现了这个功能,其中还有可改进的地方,欢迎留言讨论改进。
完整代码放在附件中,需要请自取。
本文所用CV2模块版本为opencv-python== 4.5.2.52

实现流程

主流程:

Created with Raphaël 2.3.0 新建窗口显示图像 鼠标左键按下为起始点 鼠标移动且左键拖拽绘制轨曲线 鼠标左键抬起 **拖拽划线区域转换为完全封闭区域** 对区域轨迹进行边缘提取
  • 首先新建图像窗口显示图像并响应鼠标事件
 	path = 'example.jpg'
    img = cv2.imread(path)
    cv2.namedWindow("")
    cv2.setMouseCallback("",on_mouse,0)
    cv2.imshow("",img)
  • 改写响应函数,当鼠标左键按下时,描绘一个点并作为起始点
if  event == cv2.EVENT_LBUTTONDOWN:
        Start_point = [x,y] #获取起始点,并保存
        points.append(Start_point)
        cv2.circle(img,tuple(Start_point),1,(255,255,255),0)
        cv2.imshow("",img)
  • 当鼠标在图像上移动且为左键拖拽状态时,按照鼠标轨迹绘制线
elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
        Cur_point = [x,y]
        # print(points)
        cv2.line(img,tuple(points[-1]),tuple(Cur_point),(255,255,255)) #以上一个点和当前点为起始和结束点,绘制轨迹
        cv2.imshow("",img)
        points.append(Cur_point)
  • 当鼠标左键抬起时,记录此时点为终点,由于我们所选择区域必须为封闭区域,所以将终点坐标改为起点坐标,绘制完整轮廓。
elif event == cv2.EVENT_LBUTTONUP:
        Cur_point=Start_point
        cv2.line(img,tuple(points[-1]),tuple(Cur_point),(255,255,255))
        cv2.circle(img,tuple(Cur_point),1,(255,255,255))
  • 由于鼠标响应或移动过快,此时绘制的轨迹线并不是一个完全封闭的曲线(会存在一些缺失点),所以采用了泛洪填充算法使轨迹曲线完全闭合。
cv2.floodFill(img,mask_img,(x,y),(255,255,255),cv2.FLOODFILL_FIXED_RANGE)
  • 最后对完整轨迹线的图像进行二值化处理后进行轮廓识别,将得到的轮廓图像作为模板,保留模板区域内的图像。
    PS:此处创建一个模板cimg,然后绘制刚才轮廓,且将轮廓内像素外设置为(0,0,0),cv2.bitwise_or()函数作用是按位或。
		cimg = np.zeros_like(img)
        cimg[:, :, :] = 255
        cv2.drawContours(cimg, contours, 1, color=(0, 0, 0), thickness=-1)
        cv2.imshow('mask', cimg)  # 将零件区域像素值设为(0, 0, 0)
        cv2.waitKey(0)

        final = cv2.bitwise_or(copyImg, cimg)

结果分析

第一行中左边位原始图像,右为鼠标绘制的任意区域
第二行中左边为模板图像,右为依据模板得到的绘制区域的截图
Python CV2图像鼠标选择任意区域截图_第1张图片

附件

import cv2
import os
import numpy as np
import copy

points = []
def on_mouse(event,x,y,flags,param):
    global points, img,Cur_point,Start_point 
    copyImg = copy.deepcopy(img)
    h,w = img.shape[:2]
    mask_img = np.zeros([h+2,w+2],dtype=np.uint8)
    if  event == cv2.EVENT_LBUTTONDOWN:
        Start_point = [x,y]
        points.append(Start_point)
        cv2.circle(img,tuple(Start_point),1,(255,255,255),0)
        cv2.imshow("",img)
    elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
        Cur_point = [x,y]
        # print(points)
        cv2.line(img,tuple(points[-1]),tuple(Cur_point),(255,255,255))
        cv2.imshow("",img)
        points.append(Cur_point)
    elif event == cv2.EVENT_LBUTTONUP:
        Cur_point=Start_point
        cv2.line(img,tuple(points[-1]),tuple(Cur_point),(255,255,255))
        cv2.circle(img,tuple(Cur_point),1,(255,255,255))
        ret, image, mask, rect  = cv2.floodFill(img,mask_img,(x,y),(255,255,255),cv2.FLOODFILL_FIXED_RANGE)
        cv2.imwrite("maskImage.jpg",img)
        print(np.shape(image))
        segImg = np.zeros((h,w,3),np.uint8)
        src =cv2.bitwise_and(img,image)
        cv2.imwrite("segImg.jpg",src)
        cv2.waitKey(0)
        img = cv2.imread('segImg.jpg')
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        #ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)  # opencv里面画轮廓是根据白色像素来画的,所以反转一下。
        ret, binary = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
        contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        contours.sort(key=lambda c: cv2.contourArea(c), reverse=True)
        cv2.drawContours(copyImg, contours, -1, (0, 0, 255), 3)
        cv2.imshow('RoiImg', copyImg)  # 只显示零件外轮廓
        cv2.waitKey(0)
        cimg = np.zeros_like(img)
        cimg[:, :, :] = 255
        cv2.drawContours(cimg, contours, 1, color=(0, 0, 0), thickness=-1)
        cv2.imshow('maskImg', cimg)  # 将零件区域像素值设为(0, 0, 0)
        cv2.waitKey(0)
        final = cv2.bitwise_or(copyImg, cimg)
        cv2.imshow('finalImg', final)  # 执行或操作后生成想要的图片
        cv2.waitKey(0)
if __name__ == "__main__":
    path = 'example.jpg'
    img = cv2.imread(path)
    cv2.namedWindow("")
    cv2.setMouseCallback("",on_mouse,0)
    cv2.imshow("",img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

你可能感兴趣的:(python,opencv,图像处理)