SoFunction
Updated on 2024-11-17

Dynamic drawing of rectangles and polygons and saving coordinates based on OpenCV.

Right now you can only draw rectangles and polygons one at a time, do you still need to modify it so that you can draw more than one at a time?

1 Draw rectangles and polygons, mode controlled by keyboard

# Draw rectangles and polygons differently with the keyboard s and p and save the coordinates
# Drawing rectangles comes with OPencv and can only be ended by pressing enter
 
import copy
import json
import joblib
import cv2
import numpy as np
import os
import  as plt
import imutils
from win32 import win32gui, win32print
from  import win32con
WIN_NAME = 'draw_rect'
 
 
 
def get_list0(path):
    if not (path):
        print("The document recording the location of the standard for the model is missing/ or the input model does not match the name of its corresponding standard document.")
    file1 = open(path, 'r')
    lines = ()
    # for line in lines:
    #     if (any(kw in line for kw in kws)):
    #         (line + '\n')
    zb0, list0 = [], []
    for i in range(len(lines)):  # Take the coordinates
        if lines[i] != '(pt1,pt2):\n':
            (lines[i][:-1])
    # print(zb0)
    for i in range(0, len(zb0)):  # Convert integers
        zb0[i] = int(zb0[i])
    # print(zb0)
 
    for i in range(0, len(zb0), 4):  # Taken every four and added to the list
        x0, y0, x1, y1 = zb0[i: i + 4]
 
        # Make the point set to top left to bottom right
        if y1<=y0:
            temp = y0
            y0 = y1
            y1 = temp
 
        # print(x0,y0,x1,y1)
        ([x0, y0, x1, y1])
    print("list0:", list0)
    ()
    return list0
 
 
'''
        Initial verification file, the file name represents the type, when checking read the file name as the type judgment criteria
        Open course folder, read the original picture of standard parts, save the standard position to biaozhun/labels, save the picture with standard position to biaozhun/imgs.
'''
def define_start(img_name, img_path, type):
    pts = []  # For repositories
 
    def draw_roi(event, x, y, flags, param):
        img2 = ()
        # print("----------")
        # ("img2", img2)
        # (0)
 
        if event == cv2.EVENT_LBUTTONDOWN:  # Left click, select point
            ((x, y))
 
        if event == cv2.EVENT_RBUTTONDOWN:  # Right-click to cancel the most recently selected point
            ()
 
        if event == cv2.EVENT_MBUTTONDOWN:  # Middle key to draw contours
 
            (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:
            # Draw the last point in the pts.
            (img2, pts[-1], 3, (0, 0, 255), -1)
 
        if len(pts) > 1:
            # Drawing lines
            for i in range(len(pts) - 1):
                (img2, pts[i], 5, (0, 0, 255), -1)  # x ,y are the coordinates of the place where the mouse clicked.
                (img=img2, pt1=pts[i], pt2=pts[i + 1], color=(255, 0, 0), thickness=2)
            (img=img2, pt1=pts[0], pt2=pts[-1], color=(255, 0, 0), thickness=2)
 
        (WIN_NAME, img2)
 
    def set_ratio(image):
        if image is None:
            return 0, 0, 0
        # print()
        img_h, img_w = [:2]
        """Getting the true resolution."""
        hDC = (0)
        screen_w = (hDC, )  # Horizontal resolution
        screen_h = (hDC, )  # Vertical resolution
        # print(img_w,img_h)
 
        num_wh = 1
        if img_w * img_h > 1.9e7:  # Twenty million pixels
            num_wh = 4
        elif img_w * img_h > 1.0e7:  # Ten million pixels
            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) = (img_path)
 
    # file = '' # need user to select image, pass in name of image
 
    if (".jpg") or (".png"):  # If file ends in jpg
        # img_dir = (file_dir, file)
        image = (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/%" % (img_name)
        open(txt_path, 'w').close()  # Empty file data
        f = open(txt_path, mode='a+')
        txt_save = []
 
        img = (image, width = ratio_w)
        (WIN_NAME, cv2.WINDOW_NORMAL)
        # # (WIN_NAME, 2)
        (WIN_NAME, ratio_w, ratio_h)
        (WIN_NAME, img)
        # (1)
 
        key = (0)
 
        # Rectangle
        if key == ord("s"):
            roi = (windowName=WIN_NAME, img=img, showCrosshair=False, fromCenter=False)
            x, y, w, h = roi
            (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))
 
            (WIN_NAME, img)
            (0)
 
            # Save txt coordinates
            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:
                (str(txt_i) + '\n')
            print("txt_save:", txt_save)
            # break
            ()
 
            # Find the closer, delete
            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:
                (str(i) + '\n')
            ()
 
        # Polygon
        elif key == ord("p"):
            print("---")
 
            (WIN_NAME, draw_roi)
 
            while True:
                key = (1)
                if key == 13 or (WIN_NAME, 0) == -1:  # enter.
                    # Save txt coordinates
 
                    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:
                        (str(txt_i) + '\n')
                    print("txt_save:", txt_save)
                    # break
                    ()
 
                # Now it's polygons before it didn't work
                    # # Find the closer, delete
                    # 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:
                    #     (str(i) + '\n')
                    # ()
 
                    break
            ()
 
 
    else:
        print("Input image type error! Please enter an image in JPG/PNG format!")
 
 
 
if __name__ == '__main__':
    # path_file = open('./datasets/', 'r')
    path_file = open('./DataSet/', 'r')
    path_dic = (path_file)
    img_path = path_dic['path']         # # Draw the address of the standard picture
    path_file.close()
    img_name = img_path.split('\\')[-1][:-4]
    define_start(img_name, img_path, 0)

file

{"path": "D:\\ALLBuffers\\Pycharm\\OpencvRun\\DataSet\\"}

2 After the modification, the default situation is to draw polygons directly, and press the middle mouse button to switch to the mode of drawing rectangles.

## 1 The default run of the program is to draw polygons directly, by clicking directly on the
## Click on the X in the upper right corner or press enter to close the image and save the coordinates when you are done drawing.
## 2 By default, click the middle mouse button or space to switch to rectangular mode
## 3 In draw rectangle mode you can only close the image and save the coordinates by pressing enter
## 4 Left mouse button in Draw Rectangle mode to cancel the previous step or redraw the rectangle.
## 5 Right mouse button cancels the previous step when drawing polygons
 
import copy
import json
import joblib
import cv2
import numpy as np
import os
import  as plt
import imutils
from win32 import win32gui, win32print
from  import win32con
 
WIN_NAME = 'draw_rect'
 
 
def get_list0(path):
    if not (path):
        print("The document recording the location of the standard for the model is missing/ or the input model does not match the name of its corresponding standard document.")
    file1 = open(path, 'r')
    lines = ()
    # for line in lines:
    #     if (any(kw in line for kw in kws)):
    #         (line + '\n')
    zb0, list0 = [], []
    for i in range(len(lines)):  # Take the coordinates
        if lines[i] != '(pt1,pt2):\n':
            (lines[i][:-1])
    # print(zb0)
    for i in range(0, len(zb0)):  # Convert integers
        zb0[i] = int(zb0[i])
    # print(zb0)
 
    for i in range(0, len(zb0), 4):  # Taken every four and added to the list
        x0, y0, x1, y1 = zb0[i: i + 4]
 
        # Make the point set to top left to bottom right
        if y1<=y0:
            temp = y0
            y0 = y1
            y1 = temp
 
        # print(x0,y0,x1,y1)
        ([x0, y0, x1, y1])
    print("list0:", list0)
    ()
    return list0
 
 
'''
        Initial verification file, the file name represents the type, when checking read the file name as the type judgment criteria
        Open course folder, read the original picture of standard parts, save the standard position to biaozhun/labels, save the picture with standard position to biaozhun/imgs.
'''
POLYLINES = False  # Polygon to Rectangle Switch
 
 
def define_start(img_name, img_path, type):
    pts = []  # For repositories
 
    def draw_roi(event, x, y, flags, param):
 
        img2 = ()
 
        if event == cv2.EVENT_LBUTTONDOWN:  # Left click, select point
            ((x, y))
            (img2, pts[-1], 3, (0, 255, 0), -1)
        #
        # if event == cv2.EVENT_MOUSEMOVE: # draw circle
        #     if len(pts) >= 1:
        #         radius = (pow(x-pts[0][0],2) + pow(y-pts[0][1],2))
        #         radius = int(radius)
        #         (radius)
        # (img2, pts[0], rs[-1], (0, 0, 255), 2) # x ,y are the coordinates of the place where the mouse clicked.
        #
 
 
        if event == cv2.EVENT_RBUTTONDOWN:  # Right-click to cancel the most recently selected point
            if len(pts) >= 1:
                ()
 
 
        if event == cv2.EVENT_MBUTTONDOWN:  # Middle key to draw contours
            global POLYLINES
            # print("MBUTTONDOWN: # Middle button draws outline")
            POLYLINES = True
 
        if len(pts) > 0:
            # Draw the last point in the pts.
            (img2, pts[-1], 3, (0, 255, 0), -1)
 
 
        if len(pts) > 1:
 
            # Drawing lines
            for i in range(len(pts) - 1):
                (img2, pts[i], 5, (0, 255, 0), -1)  # x ,y are the coordinates of the place where the mouse clicked.
                (img=img2, pt1=pts[i], pt2=pts[i + 1], color=(0, 0, 255), thickness=2)
            (img=img2, pt1=pts[0], pt2=pts[-1], color=(0, 0, 255), thickness=2)
 
        (WIN_NAME, img2)
 
    def set_ratio(image):
        if image is None:
            return 0, 0, 0
        # print()
        img_h, img_w = [:2]
        """Getting the true resolution."""
        hDC = (0)
        screen_w = (hDC, )  # Horizontal resolution
        screen_h = (hDC, )  # Vertical resolution
        # print(img_w,img_h)
 
        num_wh = 1
        if img_w * img_h > 1.9e7:  # Twenty million pixels
            num_wh = 4
        elif img_w * img_h > 1.0e7:  # Ten million pixels
            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) = (img_path)
 
    # file = '' # need user to select image, pass in name of image
 
    if (".jpg") or (".png"):  # If file ends in jpg
        # img_dir = (file_dir, file)
        image = (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/%" % (img_name)
        open(txt_path, 'w').close()  # Empty file data
        f = open(txt_path, mode='a+')
        txt_save = []
 
        img = (image, width = ratio_w)
        (WIN_NAME, cv2.WINDOW_NORMAL)
        (WIN_NAME, ratio_w, ratio_h)
        (WIN_NAME, img)
 
        # Default direct execution of drawing polygons
        (WIN_NAME, draw_roi)
 
        while True:
            w_key = (1)
            # enter or Return: # enter or Return: # enter or Return: # enter or Return: # enter or Return.
            if w_key == 13 or (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:
                    (str(txt_i) + '\n')
                print("txt_save:", txt_save)
                break
                ()
 
                # Now it's polygons before it didn't work
                # # Find the ones that are close and delete them
                # 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:
                #     (str(i) + '\n')
                # ()
 
            # Space to Rectangle
            if POLYLINES == True or w_key == 32:
                roi = (windowName=WIN_NAME, img=img, showCrosshair=False, fromCenter=False)
                x, y, w, h = roi
                (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))
 
                # Show ROI in red box
                # (WIN_NAME, img)
                # (0)
 
                # Save txt coordinates
                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:
                    (str(txt_i) + '\n')
                print("txt_save:", txt_save)
                # break
                ()
 
                # Find the closer, delete
                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:
                    (str(i) + '\n')
                ()
                break
        ()
 
    else:
        print("Input image type error! Please enter an image in JPG/PNG format!")
 
 
if __name__ == '__main__':
    # path_file = open('./datasets/', 'r')
    path_file = open('./DataSet/', 'r')
    path_dic = (path_file)
    img_path = path_dic['path']         # # Draw the address of the standard picture
    path_file.close()
    img_name = img_path.split('\\')[-1][:-4]
    define_start(img_name, img_path, 0)

The above is based on OpenCV to achieve dynamic drawing of rectangles and polygons and save the coordinates of the details, more information about OpenCV dynamic drawing of rectangles and polygons, please pay attention to my other related articles!