How do I crop Fixed Patches around the red dots in an image

Viewed 132

I am new to OpenCV and I am not even sure how to tackle this problem. I have this image of 500x500 pixel with red dots and white lines in it.

enter image description here

Considering each red dot as center and could I draw a fixed bounding box of 25X25 size around the red dot? I need to identify every red dot in the image.

enter image description here

Note: condition is that I need to find a bounding box of fixed size (25x25) and the red dot must be in the center of the bounding box.

Any help would be appreciated. Thank you in advance.

2 Answers

Another solution, using numpy slicing to get the red channel, where to create a mask of the red dots and cv2.findContours to get the bounding rectangles of the dots. We can use this info to draw the new 25 x 25 rectangles:

# Imports
import cv2
import numpy as np

# Read image
imagePath = "C://opencvImages//"
inputImage = cv2.imread(imagePath + "oHk9s.png")

# Deep copy for results:
inputImageCopy = inputImage.copy()

# Slice the Red channel from the image:
r = inputImage[:, :, 2]
# Convert type to unsigned integer (8 bit):
r = np.where(r == 237, 255, 0).astype("uint8")

# Extract blobs (the red dots are all the white pixels in this mask):
contours, _ = cv2.findContours(r, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# Store bounding rectangles here:
boundingRectangles = []

# Loop through the blobs and draw a 25 x 25 green rectangle around them:
for c in contours:
    # Get dot bounding box:
    x, y, w, h = cv2.boundingRect(c)

    # Set new bounding box dimensions:
    boxWidth = 25
    boxHeight = 25
    # Center rectangle around blob:
    boxX = int(x + 0.5 * (w - boxWidth))
    boxY = int(y + 0.5 * (h - boxHeight))

    # Store data:
    boundingRectangles.append((boxX, boxY, boxWidth, boxHeight))

    # Draw and show new bounding rectangles
    color = (0, 255, 0)
    cv2.rectangle(inputImageCopy, (boxX, boxY), (boxX + boxWidth, boxY + boxHeight), color, 2)
    cv2.imshow("Boxes", inputImageCopy)
    cv2.waitKey(0)

Additionally, I've stored the top left coordinate, width and height of the rectangles in the boundingRectangles list. This is the output:

enter image description here

Here is how you can use an HSV mask to mask out everything in your image except for the red pixels:

import cv2
import numpy as np

def draw_box(img, cnt):
    x, y, w, h = cv2.boundingRect(cnt)
    half_w = w // 2
    half_h = h // 2
    x1 = x + half_h - 12
    x2 = x + half_h + 13
    y1 = y + half_w - 12
    y2 = y + half_w + 13
    cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0))

img = cv2.imread("red_dots.png")

img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
ranges = np.array([[100, 0, 0], [179, 255, 255]])
mask = cv2.inRange(img_hsv, *ranges)
img_masked = cv2.bitwise_and(img, img, mask=mask)

img_gray = cv2.cvtColor(img_masked, cv2.COLOR_BGR2GRAY)
contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

for cnt in contours:
    draw_box(img, cnt)
    
cv2.imshow("Image", img)
cv2.waitKey(0)

Output:

enter image description here

Notice at this part of the draw_box() function:

    x1 = x + half_h - 12
    x2 = x + half_h + 13
    y1 = y + half_w - 12
    y2 = y + half_w + 13

Ideally, instead of - 12 and + 13, it should be - 12.5 and + 12.5, but there cannot be half pixels in OpenCV, or an error would be thrown.

Related