基于OpenCV实现动态画矩形和多边形并保存坐标

 更新时间:2023年03月23日 10:30:21   作者:天人合一peng  
这篇文章主要为大家详细介绍了如何利用OpenCV实现动态画矩形和多边形并保存坐标,文中的示例代码讲解详细,具有一定的参考价值,需要的可以参考一下

现在画矩形和多边形一次只能画一个,还需要修改让其一次可画多个?

1 画矩形和多边形,模式通过键盘控制

# 通过键盘s和p区别画矩形和多边形并保存坐标
# 画矩形是OPencv自带的,只能通过按enter结束
 
import copy
import json
import joblib
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
import imutils
from win32 import win32gui, win32print
from win32.lib import win32con
WIN_NAME = 'draw_rect'
 
 
 
def get_list0(path):
    if not os.path.exists(path):
        print("记录该型号标准位置的文件缺失/或输入型号与其对应标准文件名称不一致")
    file1 = open(path, 'r')
    lines = file1.readlines()
    # for line in lines:
    #     if (any(kw in line for kw in kws)):
    #         SeriousFix.write(line + '\n')
    zb0, list0 = [], []
    for i in range(len(lines)):  # 取坐标
        if lines[i] != '(pt1,pt2):\n':
            zb0.append(lines[i][:-1])
    # print(zb0)
    for i in range(0, len(zb0)):  # 转换整数
        zb0[i] = int(zb0[i])
    # print(zb0)
 
    for i in range(0, len(zb0), 4):  # 每四个取一次,加入列表
        x0, y0, x1, y1 = zb0[i: i + 4]
 
        # 使点设为左上至右下
        if y1<=y0:
            temp = y0
            y0 = y1
            y1 = temp
 
        # print(x0,y0,x1,y1)
        list0.append([x0, y0, x1, y1])
    print("list0:", list0)
    file1.close()
    return list0
 
 
'''
        初始校验文件,文件名代表类型,检验时读取文件名作为类型判断标准
        打开sourse文件夹,读取标准件原始图片,保存标准位置到biaozhun/labels,保存画有标准位置的图片到biaozhun/imgs
'''
def define_start(img_name, img_path, type):
    pts = []  # 用于存放点
 
    def draw_roi(event, x, y, flags, param):
        img2 = img.copy()
        # print("----------")
        # cv2.imshow("img2", img2)
        # cv2.waitKey(0)
 
        if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击,选择点
            pts.append((x, y))
 
        if event == cv2.EVENT_RBUTTONDOWN:  # 右键点击,取消最近一次选择的点
            pts.pop()
 
        if event == cv2.EVENT_MBUTTONDOWN:  # 中键绘制轮廓
 
            cv2.line(img=img2, pt1=pts[0], pt2=pts[-1], color=(255, 0, 0), thickness=2)
 
            for i in range(len(pts)):
                txt_save.append("(pt1,pt2):")
                txt_save.append(str(pts[i][0]))
                txt_save.append(str(pts[i][1]))
 
        if len(pts) > 0:
            # 将pts中的最后一点画出来
            cv2.circle(img2, pts[-1], 3, (0, 0, 255), -1)
 
        if len(pts) > 1:
            # 画线
            for i in range(len(pts) - 1):
                cv2.circle(img2, pts[i], 5, (0, 0, 255), -1)  # x ,y 为鼠标点击地方的坐标
                cv2.line(img=img2, pt1=pts[i], pt2=pts[i + 1], color=(255, 0, 0), thickness=2)
            cv2.line(img=img2, pt1=pts[0], pt2=pts[-1], color=(255, 0, 0), thickness=2)
 
        cv2.imshow(WIN_NAME, img2)
 
    def set_ratio(image):
        if image is None:
            return 0, 0, 0
        # print(image.shape)
        img_h, img_w = image.shape[:2]
        """获取真实的分辨率"""
        hDC = win32gui.GetDC(0)
        screen_w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)  # 横向分辨率
        screen_h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)  # 纵向分辨率
        # print(img_w,img_h)
 
        num_wh = 1
        if img_w * img_h > 1.9e7:  # 两千万像素
            num_wh = 4
        elif img_w * img_h > 1.0e7:  # 一千万像素
            num_wh = 3
        elif min(img_w, img_h) >= min(screen_w, screen_h) or \
                max(img_w, img_h) >= max(screen_w, screen_h):
            num_wh = 2
        else:
            num_wh = 1
 
        ratio_h = int(img_h / num_wh)
        ratio_w = int(img_w / num_wh)
 
        return ratio_h, ratio_w, num_wh
 
    (filepath, file) = os.path.split(img_path)
 
    # file = 'r.jpg'      # 需要用户选择图片,传入图片的名称
 
    if file.endswith(".jpg") or file.endswith(".png"):  # 如果file以jpg结尾
        # img_dir = os.path.join(file_dir, file)
        image = cv2.imread(img_path)
 
        ratio_h, ratio_w, num_wh = set_ratio(image)
        if ratio_h == 0 and ratio_w == 0 and num_wh == 0:
            print("No image")
 
        txt_path = "./DrawRect/biaozhun/labels/%s.txt" % (img_name)
        open(txt_path, 'w').close()  # 清空文件数据
        f = open(txt_path, mode='a+')
        txt_save = []
 
        img = imutils.resize(image, width = ratio_w)
        cv2.namedWindow(WIN_NAME, cv2.WINDOW_NORMAL)
        # # cv2.namedWindow(WIN_NAME, 2)
        cv2.resizeWindow(WIN_NAME, ratio_w, ratio_h)
        cv2.imshow(WIN_NAME, img)
        # cv2.waitKey(1)
 
        key = cv2.waitKey(0)
 
        # 矩形
        if key == ord("s"):
            roi = cv2.selectROI(windowName=WIN_NAME, img=img, showCrosshair=False, fromCenter=False)
            x, y, w, h = roi
            cv2.rectangle(img=img, pt1=(x, y), pt2=(x + w, y + h), color=(0, 0, 255), thickness=2)
 
            print('pt1: x = %d, y = %d' % (x, y))
            txt_save.append("(pt1,pt2):")
            txt_save.append(str(x))
            txt_save.append(str(y))
            txt_save.append(str(x + w))
            txt_save.append(str(y + h))
 
            cv2.imshow(WIN_NAME, img)
            cv2.waitKey(0)
 
            # 保存txt坐标
            num_txt_i = 0
            for txt_i in range(len(txt_save)):
                txt_i = txt_i - num_txt_i
                if txt_save[txt_i] == 'delete':
                    for j in range(6):
                        del txt_save[txt_i - j]
                    num_txt_i += 6
            for txt_i in txt_save:
                f.write(str(txt_i) + '\n')
            print("txt_save:", txt_save)
            # break
            f.close()
 
            # 查找距离较近的,删除
            points_list = get_list0(txt_path)
            new_points_list = []
            for i in points_list:
                x0, y0, x1, y1 = i[0], i[1], i[2], i[3]
                if abs(x1 - x0) > 5 and abs(y1 - y0) > 5:
                    new_points_list.append('(pt1,pt2):')
                    new_points_list.append(x0)
                    new_points_list.append(y0)
                    new_points_list.append(x1)
                    new_points_list.append(y1)
            print(new_points_list)
            file2 = open(txt_path, 'w')
            for i in new_points_list:
                file2.write(str(i) + '\n')
            file2.close()
 
        # 多边形
        elif key == ord("p"):
            print("---")
 
            cv2.setMouseCallback(WIN_NAME, draw_roi)
 
            while True:
                key = cv2.waitKey(1)
                if key == 13 or cv2.getWindowProperty(WIN_NAME, 0) == -1:  # enter回车键:
                    # 保存txt坐标
 
                    for i in range(len(pts)):
                        txt_save.append("(pt1,pt2):")
                        txt_save.append(str(pts[i][0]))
                        txt_save.append(str(pts[i][1]))
 
                    num_txt_i = 0
                    for txt_i in range(len(txt_save)):
                        txt_i = txt_i - num_txt_i
                        if txt_save[txt_i] == 'delete':
                            for j in range(6):
                                del txt_save[txt_i - j]
                            num_txt_i += 6
                    for txt_i in txt_save:
                        f.write(str(txt_i) + '\n')
                    print("txt_save:", txt_save)
                    # break
                    f.close()
 
                # 现在是多边形之前的方法不行
                    # # 查找距离较近的,删除
                    # points_list = get_list0(txt_path)
                    # new_points_list = []
                    # for i in points_list:
                    #     x0, y0, x1, y1 = i[0], i[1], i[2], i[3]
                    #     if abs(x1 - x0) > 5 and abs(y1 - y0) > 5:
                    #         new_points_list.append('(pt1,pt2):')
                    #         new_points_list.append(x0)
                    #         new_points_list.append(y0)
                    #         new_points_list.append(x1)
                    #         new_points_list.append(y1)
                    # print(new_points_list)
                    # file2 = open(txt_path, 'w')
                    # for i in new_points_list:
                    #     file2.write(str(i) + '\n')
                    # file2.close()
 
                    break
            cv2.destroyAllWindows()
 
 
    else:
        print("输入图片类型错误!请输入JPG/PNG格式的图片!")
 
 
 
if __name__ == '__main__':
    # path_file = open('./datasets/drawPath.json', 'r')
    path_file = open('./DataSet/drawPath.json', 'r')
    path_dic = json.load(path_file)
    img_path = path_dic['path']         # # 绘制标准图片的地址
    path_file.close()
    img_name = img_path.split('\\')[-1][:-4]
    define_start(img_name, img_path, 0)

drawPath.json文件

{"path": "D:\\ALLBuffers\\Pycharm\\OpencvRun\\DataSet\\smpj.jpg"}

2 修改后默认情况下直接画多边形,按鼠标中键切换为画矩形模式

## 1 程序默认运行是直接绘多边形,直接点击即可,
## 绘制完成后点击右上角的X或按enter即可关闭图像并保存坐标
## 2 在默认情况下,单击鼠标中键或空格即可切换为矩形模式
## 3 在绘制矩形模式下只能通过按enter关闭图像并保存坐标
## 4 在绘制矩形模式下鼠标左键取消上一步操作或重新绘制矩形
## 5 在绘制多边形时鼠标右键取消上一步操作
 
import copy
import json
import joblib
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
import imutils
from win32 import win32gui, win32print
from win32.lib import win32con
 
WIN_NAME = 'draw_rect'
 
 
def get_list0(path):
    if not os.path.exists(path):
        print("记录该型号标准位置的文件缺失/或输入型号与其对应标准文件名称不一致")
    file1 = open(path, 'r')
    lines = file1.readlines()
    # for line in lines:
    #     if (any(kw in line for kw in kws)):
    #         SeriousFix.write(line + '\n')
    zb0, list0 = [], []
    for i in range(len(lines)):  # 取坐标
        if lines[i] != '(pt1,pt2):\n':
            zb0.append(lines[i][:-1])
    # print(zb0)
    for i in range(0, len(zb0)):  # 转换整数
        zb0[i] = int(zb0[i])
    # print(zb0)
 
    for i in range(0, len(zb0), 4):  # 每四个取一次,加入列表
        x0, y0, x1, y1 = zb0[i: i + 4]
 
        # 使点设为左上至右下
        if y1<=y0:
            temp = y0
            y0 = y1
            y1 = temp
 
        # print(x0,y0,x1,y1)
        list0.append([x0, y0, x1, y1])
    print("list0:", list0)
    file1.close()
    return list0
 
 
'''
        初始校验文件,文件名代表类型,检验时读取文件名作为类型判断标准
        打开sourse文件夹,读取标准件原始图片,保存标准位置到biaozhun/labels,保存画有标准位置的图片到biaozhun/imgs
'''
POLYLINES = False  # 多边形向矩形切换
 
 
def define_start(img_name, img_path, type):
    pts = []  # 用于存放点
 
    def draw_roi(event, x, y, flags, param):
 
        img2 = img.copy()
 
        if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击,选择点
            pts.append((x, y))
            cv2.circle(img2, pts[-1], 3, (0, 255, 0), -1)
        #
        # if event == cv2.EVENT_MOUSEMOVE:  # 画圆
        #     if len(pts) >= 1:
        #         radius = np.sqrt(pow(x-pts[0][0],2) + pow(y-pts[0][1],2))
        #         radius = int(radius)
        #         rs.append(radius)
        #         cv2.circle(img2, pts[0], rs[-1], (0, 0, 255), 2)  # x ,y 为鼠标点击地方的坐标
        #
 
 
        if event == cv2.EVENT_RBUTTONDOWN:  # 右键点击,取消最近一次选择的点
            if len(pts) >= 1:
                pts.pop()
 
 
        if event == cv2.EVENT_MBUTTONDOWN:  # 中键绘制轮廓
            global POLYLINES
            # print("MBUTTONDOWN:  # 中键绘制轮廓")
            POLYLINES = True
 
        if len(pts) > 0:
            # 将pts中的最后一点画出来
            cv2.circle(img2, pts[-1], 3, (0, 255, 0), -1)
 
 
        if len(pts) > 1:
 
            # 画线
            for i in range(len(pts) - 1):
                cv2.circle(img2, pts[i], 5, (0, 255, 0), -1)  # x ,y 为鼠标点击地方的坐标
                cv2.line(img=img2, pt1=pts[i], pt2=pts[i + 1], color=(0, 0, 255), thickness=2)
            cv2.line(img=img2, pt1=pts[0], pt2=pts[-1], color=(0, 0, 255), thickness=2)
 
        cv2.imshow(WIN_NAME, img2)
 
    def set_ratio(image):
        if image is None:
            return 0, 0, 0
        # print(image.shape)
        img_h, img_w = image.shape[:2]
        """获取真实的分辨率"""
        hDC = win32gui.GetDC(0)
        screen_w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)  # 横向分辨率
        screen_h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)  # 纵向分辨率
        # print(img_w,img_h)
 
        num_wh = 1
        if img_w * img_h > 1.9e7:  # 两千万像素
            num_wh = 4
        elif img_w * img_h > 1.0e7:  # 一千万像素
            num_wh = 3
        elif min(img_w, img_h) >= min(screen_w, screen_h) or \
                max(img_w, img_h) >= max(screen_w, screen_h):
            num_wh = 2
        else:
            num_wh = 1
 
        ratio_h = int(img_h / num_wh)
        ratio_w = int(img_w / num_wh)
 
        return ratio_h, ratio_w, num_wh
 
    (filepath, file) = os.path.split(img_path)
 
    # file = 'r.jpg'      # 需要用户选择图片,传入图片的名称
 
    if file.endswith(".jpg") or file.endswith(".png"):  # 如果file以jpg结尾
        # img_dir = os.path.join(file_dir, file)
        image = cv2.imread(img_path)
 
        ratio_h, ratio_w, num_wh = set_ratio(image)
        if ratio_h == 0 and ratio_w == 0 and num_wh == 0:
            print("No image")
 
        txt_path = "./DrawRect/biaozhun/labels/%s.txt" % (img_name)
        open(txt_path, 'w').close()  # 清空文件数据
        f = open(txt_path, mode='a+')
        txt_save = []
 
        img = imutils.resize(image, width = ratio_w)
        cv2.namedWindow(WIN_NAME, cv2.WINDOW_NORMAL)
        cv2.resizeWindow(WIN_NAME, ratio_w, ratio_h)
        cv2.imshow(WIN_NAME, img)
 
        # 默认直接执行画多边形
        cv2.setMouseCallback(WIN_NAME, draw_roi)
 
        while True:
            w_key = cv2.waitKey(1)
            # enter 或回车键:
            if w_key == 13 or cv2.getWindowProperty(WIN_NAME, 0) == -1:
                for i in range(len(pts)):
                    if i == 0:
                      txt_save.append("(pt1,pt2):")
                    txt_save.append(str(pts[i][0]))
                    txt_save.append(str(pts[i][1]))
 
                num_txt_i = 0
                for txt_i in range(len(txt_save)):
                    txt_i = txt_i - num_txt_i
                    if txt_save[txt_i] == 'delete':
                        for j in range(6):
                            del txt_save[txt_i - j]
                        num_txt_i += 6
                for txt_i in txt_save:
                    f.write(str(txt_i) + '\n')
                print("txt_save:", txt_save)
                break
                f.close()
 
                # 现在是多边形之前的方法不行
                # # 查找距离较近的,删除
                # points_list = get_list0(txt_path)
                # new_points_list = []
                # for i in points_list:
                #     x0, y0, x1, y1 = i[0], i[1], i[2], i[3]
                #     if abs(x1 - x0) > 5 and abs(y1 - y0) > 5:
                #         new_points_list.append('(pt1,pt2):')
                #         new_points_list.append(x0)
                #         new_points_list.append(y0)
                #         new_points_list.append(x1)
                #         new_points_list.append(y1)
                # print(new_points_list)
                # file2 = open(txt_path, 'w')
                # for i in new_points_list:
                #     file2.write(str(i) + '\n')
                # file2.close()
 
            # 空格切换至矩形
            if POLYLINES == True or w_key == 32:
                roi = cv2.selectROI(windowName=WIN_NAME, img=img, showCrosshair=False, fromCenter=False)
                x, y, w, h = roi
                cv2.rectangle(img=img, pt1=(x, y), pt2=(x + w, y + h), color=(0, 0, 255), thickness=2)
 
                print('pt1: x = %d, y = %d' % (x, y))
                txt_save.append("(pt1,pt2):")
                txt_save.append(str(x))
                txt_save.append(str(y))
                txt_save.append(str(x + w))
                txt_save.append(str(y + h))
 
                # 用红色框显示ROI
                # cv2.imshow(WIN_NAME, img)
                # cv2.waitKey(0)
 
                # 保存txt坐标
                num_txt_i = 0
                for txt_i in range(len(txt_save)):
                    txt_i = txt_i - num_txt_i
                    if txt_save[txt_i] == 'delete':
                        for j in range(6):
                            del txt_save[txt_i - j]
                        num_txt_i += 6
                for txt_i in txt_save:
                    f.write(str(txt_i) + '\n')
                print("txt_save:", txt_save)
                # break
                f.close()
 
                # 查找距离较近的,删除
                points_list = get_list0(txt_path)
                new_points_list = []
                for i in points_list:
                    x0, y0, x1, y1 = i[0], i[1], i[2], i[3]
                    if abs(x1 - x0) > 5 and abs(y1 - y0) > 5:
                        new_points_list.append('(pt1,pt2):')
                        new_points_list.append(x0)
                        new_points_list.append(y0)
                        new_points_list.append(x1)
                        new_points_list.append(y1)
                print(new_points_list)
                file2 = open(txt_path, 'w')
                for i in new_points_list:
                    file2.write(str(i) + '\n')
                file2.close()
                break
        cv2.destroyAllWindows()
 
    else:
        print("输入图片类型错误!请输入JPG/PNG格式的图片!")
 
 
if __name__ == '__main__':
    # path_file = open('./datasets/drawPath.json', 'r')
    path_file = open('./DataSet/drawPath.json', 'r')
    path_dic = json.load(path_file)
    img_path = path_dic['path']         # # 绘制标准图片的地址
    path_file.close()
    img_name = img_path.split('\\')[-1][:-4]
    define_start(img_name, img_path, 0)

以上就是基于OpenCV实现动态画矩形和多边形并保存坐标的详细内容,更多关于OpenCV动态画矩形 多边形的资料请关注脚本之家其它相关文章!

相关文章

  • wxpython自定义下拉列表框过程图解

    wxpython自定义下拉列表框过程图解

    这篇文章主要介绍了wxpython自定义下拉列表框过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Pytest自动化测试的具体使用

    Pytest自动化测试的具体使用

    Pytest是一个Python的自动化测试框架,它可用于编写单元测试、功能测试、集成测试和端到端测试,本文就来介绍一下Pytest自动化测试的具体使用,感兴趣的可以了解一下
    2024-01-01
  • 解决Python中list里的中文输出到html模板里的问题

    解决Python中list里的中文输出到html模板里的问题

    今天小编就为大家分享一篇解决Python中list里的中文输出到html模板里的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • Python中类的mro与继承关系详解(二)

    Python中类的mro与继承关系详解(二)

    这篇文章主要介绍了Python中类的mro与继承关系详解,上一篇我们已经通过mro相关资料介绍了mro继承关系的基础内容,这片紧接着上一篇文章展开详细内容,需要的朋友可以参考一下
    2022-07-07
  • pyqt5之将textBrowser的内容写入txt文档的方法

    pyqt5之将textBrowser的内容写入txt文档的方法

    今天小编就为大家分享一篇pyqt5之将textBrowser的内容写入txt文档的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06
  • python wav模块获取采样率 采样点声道量化位数(实例代码)

    python wav模块获取采样率 采样点声道量化位数(实例代码)

    这篇文章主要介绍了python wav模块获取采样率 采样点声道量化位数,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01
  • 在keras里实现自定义上采样层

    在keras里实现自定义上采样层

    这篇文章主要介绍了在keras里实现自定义上采样层,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • pytorch固定BN层参数的操作

    pytorch固定BN层参数的操作

    这篇文章主要介绍了pytorch固定BN层参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-05-05
  • Anaconda的安装与虚拟环境建立

    Anaconda的安装与虚拟环境建立

    这篇文章主要介绍了Anaconda的安装与虚拟环境建立
    2020-11-11
  • django中的数据库迁移的实现

    django中的数据库迁移的实现

    这篇文章主要介绍了django中的数据库迁移的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03

最新评论