Search code examples
pythonopencvimage-processingcrop

Crop six rectangles of an image from cv.boundingRect using OpenCV


I want to crop and export six rectangles from an image. I already obtained the x, y, width, and length of each rectangle using cv.boundingRect in an array of tuples. I thought I can just create a "for" loop to export each rectangle image but it didn't work. Here is the image:

newsample.jpg

import cv2 as cv
import numpy as np
import random as rng
from matplotlib import pyplot as plt

# Rectangle Segmentation
# Output : 16 uPAD Square

img = cv.imread('newsample.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret,thresh = cv.threshold(img, 110, 255, cv.THRESH_BINARY_INV)
median = cv.medianBlur(thresh, 13)

# Parameter: image, mode, method
contours,hierarchy = cv.findContours(median, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

# Canny Edge Detector
edges = cv.Canny(median,100,200)

contours_poly = [None]*len(contours)
boundRect = [None]*len(contours)

for i, c in enumerate(contours):

contours_poly[i] = cv.approxPolyDP(c, 3, True)
    boundRect[i] = cv.boundingRect(contours_poly[i])

drawing = np.zeros((edges.shape[0], edges.shape[1], 3), dtype=np.uint8)
        
for i in range(len(contours)):
    color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
    cv.drawContours(drawing, contours_poly, i, color)
    cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \
               (int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2)
    
cv.imshow('Contours', drawing)
cv.waitKey(0)

Solution

  • Tested only on your sample image.

    import cv2 as cv
    import numpy as np
    import random as rng
    from matplotlib import pyplot as plt
    
    # Rectangle Segmentation
    # Output : 16 uPAD Square
    
    img = cv.imread('newsample.jpg')
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)
    median = cv.medianBlur(thresh, 5)
    
    # Parameter: image, mode, method
    contours, hierarchy = cv.findContours(median, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    
    # Canny Edge Detector
    edges = cv.Canny(median, 100, 200)
    boundRect = [None] * 6
    
    contours_area = []
    
    for i, contour in enumerate(contours):
        contours_area.append(cv.contourArea(contour))
    
    sorted_areas = sorted(contours_area, reverse=True)
    interesting_rectangles = [contours[i] for i in range(len(sorted_areas)) if contours_area[i] in sorted_areas[:6]][:6]
    
    for i, c in enumerate(interesting_rectangles):
        boundRect[i] = cv.boundingRect(c)
    
    drawing = np.zeros((edges.shape[0], edges.shape[1], 3), dtype=np.uint8)
    
    for i in range(len(interesting_rectangles)):
        color = (rng.randint(0, 256), rng.randint(0, 256), rng.randint(0, 256))
        cv.rectangle(drawing, (int(boundRect[i][0]),
                               int(boundRect[i][1])),
                     (int(boundRect[i][0] + boundRect[i][2]),
                      int(boundRect[i][1] + boundRect[i][3])), color, 2)
    
    rectangle_data = []
    
    for i, item in enumerate(boundRect):
        rectangle_data.append(img[item[1]:item[1] + item[3], item[0]:item[0] + item[2], :])
        
    for i, item in enumerate(rectangle_data):
        cv.imwrite(f"./rectangle_results_{i + 1}.png", item)
    
    cv.imshow('Contours', drawing)
    cv.waitKey(0)