0

i was trying to find rectangles the size i choose. using the box width and box height in the code but i find all sorts of rectangle sizes.

i have my test pattern image. to see it when you run the program, first have two monitors, second run the program and move the pop up window to the monitor the program is not showing in the pop up window.

my program does not detect rectangles that are divided with lines and have random letters and numbers touching it.

that is my first problem in the test pattern this is the top picture.

the second problem is the bottom image in the test picture, that is i get too many results in the one image when i tweak the canny and approxPolyDP numerical values to allow for more results. but i'm just trying to find the rectangles the size i want.

here is my code and my test picture:

test picture

to use the test picture run the program and video the test picture through the window that is showing video of your desktop.

here is my code, its in python 3:

import numpy as np
import cv2
from mss import mss
from PIL import Image
import imutils

sct = mss()
BOX_WIDTH = 235
BOX_HEIGHT = 10

while 1:
    w, h = 240, 640
    monitor = {'top': 100, 'left': 900, 'width': w, 'height': h}

    img = Image.frombytes('RGB', (w, h), sct.grab(monitor).rgb)

    image_data = np.asarray(img)

    # Convert the image to grayscale

    gray = cv2.cvtColor(image_data, cv2.COLOR_BGR2GRAY)

    # Perform Canny edge detection

    edges = cv2.Canny(gray, 600900, 150) # i don't know what these values should be? so i used 900, 150 which makes less results

    # Find contours in the edges image

    hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    contours = imutils.grab_contours(hierarchy)

    # Iterate over each contour

    for contour in contours:

        # Approximate the contour to a polygon

        polygon = cv2.approxPolyDP(contour, 0.01004 * cv2.arcLength(contour, True), True)  # detects if its a square or rectangle

        # Check if the polygon has 4 sides

        if len(polygon) <= 11:
            # Draw the rectangle on the image

            x, y, w, h = cv2.boundingRect(contour)  # changed polygon to contour

            ratio = float(w) / h
            length = cv2.arcLength(contour, True)
            half_width = BOX_WIDTH // 2
            lift_height = BOX_HEIGHT // 6

            if (length <= 950) and (length >= 100):
                if not ((ratio >= 0.99) and (ratio <= 1.0)):
                    cv2.rectangle(image_data, (x, y), (x + half_width, y + BOX_HEIGHT - lift_height), (0, 0, 255), 2)  # draws green box around rectangle
                else:
                    cv2.rectangle(image_data, (x, y), (x + half_width, y + BOX_HEIGHT - lift_height), (0, 0, 255), 2)  # draws green box around square

        # Show the result

    cv2.imshow('test', image_data)
    if cv2.waitKey(25) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        break 


to fix my first problem, i have tried looking at number 4 in the list in the line its called "4. Contour Approximation", here is the link to the documentation:

https://docs.opencv.org/4.x/dd/d49/tutorial_py_contour_features.html

i tried some test code and it didn't fix it. i have since lost the test code.

for my second problem i have tried adjusting the values in my code. the canny, the approxPolyDP, the len(polygon).

edit. i fixed my problem i put the good code in the first post, edit i found out how i can post the answer so i undo edit and put old bad code in this post again. now i go make the answer reply.

2 Answers 2

0

in case you use obs studio version 29.1.3, as of today some days ago i read the opencv update notes and it said opencv can run the obs studio virtual camera!

you can use the (sources, display capture), then (start virtual camera), and this way you can get the desktop video and have access to the stuff videocapture offers too!

below is the code i use when using obs studio to capture my desktop screen:

# for desktop capture, find the rectangle of a specific width and height
#
# running the program pops up a window to watch the video.
# the program video window shows the first monitor,
# but watch the program video window on second extended monitor 

import cv2
import imutils

# Path to video file
cap = cv2.VideoCapture(
    1,
    apiPreference=cv2.CAP_ANY,
    params=[cv2.CAP_PROP_FRAME_WIDTH, 1280, cv2.CAP_PROP_FRAME_HEIGHT, 720],
)  # I made cap = 1280, 720 resolution to speed the program up on my computer. I have a rtx 3060, obs studio at 60 fps

# Used as counter variable
count = 1

# checks whether frames were extracted
success = 1

# the size of the red box that's around the found rectangle
BOX_WIDTH = 170
BOX_HEIGHT = 26

while success:

    # function extract frames
    success, image = cap.read()

    if count <= 1:
        # Saves the frames with frame-count
        cv2.imwrite("frame_%d.jpg" % count, image, [int(cv2.IMWRITE_JPEG_QUALITY), 100])  # jpg 100% quality

        count += 1

    if count == 2:
        count = 1
        frame = cv2.imread('frame_1.jpg')

        # Perform Canny edge detection

        edges = cv2.Canny(frame, 100, 200)

        # Find contours in the edges image

        hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

        contours = imutils.grab_contours(hierarchy)

        # Iterate over each contour

        for contour in contours:

            # Approximate the contour to a polygon, detects if it's a square or rectangle

            # increase "dial" until you see the box around the rectangle your targeting

            dial = 0.014  # if you change the resolution then this will probably have to be recalibrated

            polygon = cv2.approxPolyDP(contour, dial * cv2.arcLength(contour, True), True)

            # Check if the polygon has 4 sides

            if len(polygon) == 4:
                # Draw the rectangle on the image

                contour_x, contour_y, contour_width, contour_height = cv2.boundingRect(contour)

                ratio = float(contour_width) / contour_height
                half_width = BOX_WIDTH // 2
                lift_height = BOX_HEIGHT // 6

                # I can set the size of the rectangles I find with this line
                # comment out the below if line when you find rectangle with the "dial" variable above
                # (set the below if condition contour_width, contour_height,
                # until you see the box around your rectangle you found with "dial")
                if (contour_width == 59) and (contour_height == 20):
                    # draws green box around rectangle
                    # in (contour_x - 4, contour_y - 4), the 4 is to move the drawn green box over the picture
                    cv2.rectangle(frame, (contour_x - 4, contour_y - 4),
                                  (contour_x + half_width, contour_y + BOX_HEIGHT - lift_height), (0, 255, 0), 2)

            # Show the result

        cv2.imshow('test', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()





0

This code below works different than the previous code because this code finds color and I made the color to be the color of a rectangle I was searching for.

I included a slider so you could change the color you search for, and when you find it, the program puts a red rectangle over what it found.

# for desktop capture, find the rectangle of a specific width and height
#
# running the program pops up a window to watch the video.
# the program video window shows the first monitor,
# but watch the program video window on second extended monitor

import cv2
import numpy as np  # used for finding the color of the rectangle

# start of section for the "to_slide_Color()" function

def fun(x):
    pass

# Window for trackbar
cv2.namedWindow("Detection",cv2.WINDOW_NORMAL)
cv2.resizeWindow('Detection', 500, 500)

cv2.createTrackbar("L_hue", "Detection", 24, 255, fun)
cv2.createTrackbar("L_sat", "Detection", 134, 255, fun)
cv2.createTrackbar("L_val", "Detection", 238, 255, fun)

cv2.createTrackbar("up_hue", "Detection", 120, 180, fun)
cv2.createTrackbar("up_sat", "Detection", 187, 255, fun)
cv2.createTrackbar("up_val", "Detection", 255, 255, fun)

def to_slide_Color():
    # Get positions of trackbars
    L_hue = cv2.getTrackbarPos("L_hue", "Detection")
    L_sat = cv2.getTrackbarPos("L_sat", "Detection")
    L_val = cv2.getTrackbarPos("L_val", "Detection")

    up_hue = cv2.getTrackbarPos("up_hue", "Detection")
    up_sat = cv2.getTrackbarPos("up_sat", "Detection")
    up_val = cv2.getTrackbarPos("up_val", "Detection")

    return L_hue, L_sat, L_val, \
        up_hue, up_sat, up_val

# end of section for the "to_slide_Color()" function

# start  of section for opening the video and creating counter variable

# Path to video file
cap = cv2.VideoCapture(
    1,
    apiPreference=cv2.CAP_ANY,
    params=[cv2.CAP_PROP_FRAME_WIDTH, 1280, cv2.CAP_PROP_FRAME_HEIGHT, 720],
)  # I made cap = 1280, 720 resolution to speed the program up on my computer. I have a rtx 3060, obs studio at 60 fps

# Used as counter variable, it's not specific to either the finding the rectangle shape or the rectangle color
count = 1

# end  of section for opening the video and creating counter variable

while True:
    (lower_hue, lower_saturation, lower_value,
     upper_hue, upper_saturation, upper_value) = to_slide_Color()
    # this is the start of finding the color of the rectangle

    # function extract frames
    success, image = cap.read()

    if count <= 1:
        # Saves the frames with frame-count
        cv2.imwrite("frame_%d.jpg" % count, image, [int(cv2.IMWRITE_JPEG_QUALITY), 100])  # jpg 100% quality

        count += 1

    if count == 2:
        count = 1
        frame = cv2.imread('frame_1.jpg')

        # Convert BGR to HSV
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

        # define range of blue color in HSV
        lower_blue = np.array([lower_hue, lower_saturation, lower_value])
        upper_blue = np.array([upper_hue, upper_saturation, upper_value])

        # Threshold the HSV image to get only blue colors
        blue_mask = cv2.inRange(hsv, lower_blue, upper_blue)

        blue_contours = cv2.findContours(blue_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

        red = 255
        red_line_thickness = 1

        if len(blue_contours) > 0:
            blue_area = max(blue_contours, key=cv2.contourArea)
            (x, y, width, height) = cv2.boundingRect(blue_area)
            cv2.rectangle(frame, (x - 3, y - 2), (x + width, y + height), (0, 0, red), red_line_thickness)

        cv2.imshow('frame', frame)
        cv2.imshow('blue_mask', blue_mask)

        # this is the end of finding the color of the rectangle

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release the video
cap.release()

# Destroy the windows
cv2.destroyAllWindows()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.