Search code examples
pythonpython-3.xopencvcomputer-visionimage-masking

OpenCV's RotatedRect has no attribute 'size' in Python3. How to work around this?


I found out that the .size.height and .size.width operators of OpenCV's RotatedRect class don't work in Python whereas they work in C++. Let me elaborate with a simplified code snippet:

cap = cv2.VideoCapture('video1.mp4')
filter = RandomClass(20)

while(cap.isOpened()):
    ret, frame = cap.read()              # Read a frame
    res = filter.classMain(frame)        # Process the frame
    if (res == 0):
        print('Success')                 # If processing completed, print Success
cap.release()

where the class definition is as follows:

import cv2
import numpy as np

class RandomClass:
    def __inti__(self):
        self.set_skip_first(True)
    def get_skip_first(self):
        return self.skip_first
    def set_skip_first(self, value):
        self.skip_first = value
    def classMain(self, frame):
        if not get_skip_first():
            self.expand_minRect(100)        # expand the minRect by 100 pixels
            # use the expanded rectangle for some other processing here
        else:
            self.set_skip_first(False)
        # create a mask with cv2.inRange
        contour = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE, offset=(0,0))[1]
        # iterate over each contour and find the index of the largest contour
        self.minRect = cv2.minAreaRect(np.array(self.contours[self.largest_contour_index]))
        # execute some other processing here
        return 0
    def expand_minRect(self, value):
        self.minRect.size.height = self.minRect.size.height + value
        self.minRect.size.width = self.minRect.size.width + value

The error I'm receiving is as follows. The exact lines work perfectly fine in the C++ version of the above code.

File "filename", line 106, in expand_minRect

self.minRect.size.height = self.minRect.size.height + value

AttributeError: 'tuple' object has no attribute 'size'

I tried the following. I was expecting the second printed value (of variable width2) to be greater than the first printed value (of variable width1) by value.

def expand_minRect(self, value):
    _,(width1, height1),_ = self.minRect
    print(width)
    self.minRect[1][0] = self.minRect[1][0] + value
    _,(width2,height2),_ = self.minRect
    print(w)

However it didn't work as the variable type of self.minRect[1][0] is Tuple and Tuples cannot be modified.

File "filename", line 111, in expand_minRect

self.minRect1[0] = self.minRect1[0] + value

TypeError: 'tuple' object does not support item assignment

I did some research, I couldn't find a Python documentation for RotatedRect but I found a stackoverflow answer stating that

Python still lacks of RotatedRect class

So all things to a side, assuming that the RotatedRect support in Python3 is incomplete, how can I work around this and expand the width and height of my minRect variable?


Solution

  • According to this tutorial, minAreaRect returns a rectangle with ((center_x,center_y),(width,height),angle). Thus, if you modify your expand_minRect to recreate it with the correct components, it should work.

    def expand_minRect(self, value):
        self.minRect = (self.minRect[0],                                          # keep the center
                        (self.minRect[1][0] + value, self.minRect[1][1] + value), # update the size
                        self.minRect[2])                                          # keep the angle
    

    Note: The problem emerges from the fact that OpenCV python has a less object-oriented implementation than OpenCV c++. It does not return a struct which enables accessing each attribute by name (like ".size"). You need to know the tuple order and assumptions for each element.