1

Im trying this code from https://github.com/longphungtuan94/ALPR_System, and have fixed most of the issues wrt opencv version mismatch. But have been unable to fix this error :-

 line 61, in segment_characters_from_plate
    c = max(cnts, key=cv2.contourArea)
cv2.error: OpenCV(4.2.0) /io/opencv/modules/imgproc/src/shapedescr.cpp:315: error: (-215:Assertion failed) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function 'contourArea'

WHAT IVE TRIED SO FAR (But none of them worked):-

OpenCV(4.0.0) assertion failed in function 'contourArea'

OpenCV Contours in Python: How to solve 'list index out of range'

(-215:Assertion failed) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function 'contourArea'

The code goes as follows :--

import cv2
import numpy as np

import imutils
from skimage.filters import threshold_local
from skimage import measure


def sort_contours_left_to_right(character_contours):
    """
    Sort contours from left to right
    """
    i = 0
    boundingBoxes = [cv2.boundingRect(c) for c in character_contours]
    (character_contours, boundingBoxes) = zip(*sorted(zip(character_contours, boundingBoxes),
                                                key=lambda b:b[1][i], reverse=False))
    return character_contours


def segment_characters_from_plate(plate_img, fixed_width):
    """
    extract the Value component from the HSV color space and apply adaptive thresholding
    to reveal the characters on the license plate
    """
    V = cv2.split(cv2.cvtColor(plate_img, cv2.COLOR_BGR2HSV))[2]
    T = threshold_local(V, 29, offset=15, method='gaussian')
    thresh = (V > T).astype('uint8') * 255
    thresh = cv2.bitwise_not(thresh)

    # resize the license plate region to a canoncial size
    plate_img = imutils.resize(plate_img, width=fixed_width)
    thresh = imutils.resize(thresh, width=fixed_width)
    bgr_thresh = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)
    bgr_thresh = np.uint8(bgr_thresh)
    # perform a connected components analysis and initialize the mask to store the locations
    # of the character candidates
    labels = measure.label(thresh, neighbors=8, background=0)
    charCandidates = np.zeros(thresh.shape, dtype='uint8')

    # loof over the unique components
    characters = []
    for label in np.unique(labels):
        # if this is the background label, ignore it
        if label == 0:
            continue
        # otherwise, construct the label mask to display only connected components for the
        # current label, then find contours in the label mask
        labelMask = np.zeros(thresh.shape, dtype='uint8')
        labelMask[labels == label] = 255
        cnts = cv2.findContours(labelMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnts = cnts[0] if imutils.is_cv2() else cnts[1]

        # ensure at least one contour was found in the mask
        if len(cnts) > 0:

            # grab the largest contour which corresponds to the component in the mask, then
            # grab the bounding box for the contour
            c = max(cnts, key=cv2.contourArea)
            (boxX, boxY, boxW, boxH) = cv2.boundingRect(c)

            # compute the aspect ratio, solodity, and height ration for the component
            aspectRatio = boxW / float(boxH)
            solidity = cv2.contourArea(c) / float(boxW * boxH)
            heightRatio = boxH / float(plate_img.shape[0])

            # determine if the aspect ratio, solidity, and height of the contour pass
            # the rules tests
            keepAspectRatio = aspectRatio < 1.0
            keepSolidity = solidity > 0.15
            keepHeight = heightRatio > 0.5 and heightRatio < 0.95

            # check to see if the component passes all the tests
            if keepAspectRatio and keepSolidity and keepHeight and boxW > 14:
                # compute the convex hull of the contour and draw it on the character
                # candidates mask
                hull = cv2.convexHull(c)
                cv2.drawContours(charCandidates, [hull], -1, 255, -1)

    _, contours, hier = cv2.findContours(charCandidates, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if contours:
        contours = sort_contours_left_to_right(contours)
        characters = []

        addPixel = 4 # value to be added to each dimension of the character
        for c in contours:
            (x,y,w,h) = cv2.boundingRect(c)
            if y > addPixel:
                y = y - addPixel
            else:
                y = 0
            if x > addPixel:
                x = x - addPixel
            else:
                x = 0
            temp = bgr_thresh[y:y+h+(addPixel*2), x:x+w+(addPixel*2)]
            characters.append(temp)
        return characters
    else:
        return None
HansHirse
  • 18,010
  • 10
  • 38
  • 67
vinita
  • 595
  • 1
  • 9
  • 24
  • @HansHirse Man it woked !!!! please write this as answer I'd like to accept it so that you get your well deserved points. – vinita Mar 04 '20 at 05:20

3 Answers3

1

The method signature of cv2.findContours changed with each major version. It's

contours, hierarchy = cv2.findContours(...)

for OpenCV 2.x.x as well as for OpenCV 4.x.x, but it's

image, contours, hierarchy = cv2.findContours(...)

for OpenCV 3.x.x.

Now, the (first) problem is the following code:

cnts = cnts[0] if imutils.is_cv2() else cnts[1]

You only check, if the used version is OpenCV 2.x.x, such that cnts[1] is also used for OpenCV 4.x.x, where it should be cnts[0], too. Better replace that imutils version checking with something like:

cnts = cnts[0] if len(cnts) == 2 else cnts[1]

Until further change of the method signature, this will work for all major versions of OpenCV.

Please notice, that there'll be another error occuring here:

_, contours, hier = cv2.findContours(...)

This is specific to OpenCV 3.x.x, so better change that line accordingly, too.

Hope that helps!

HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • cnts = cnts[0] if len(cnts) == 2 else cnts[1] is working fine. Thank you. but i have small doubt here.. Is the len(cnts) == 2 => the len is in imutils or i shall uninstall imutils package? – Manivel Gopi Jan 02 '21 at 18:19
1

@Michael Currie, Your answer is correct! I did not do contour detection, but found the contour points by other methods. I mainly focus on the area of the outline, and when I use cv2.contourArea() to solve for the area surrounded by my own defined outline points, I get the following error:

cv2.error: OpenCV(4.4.0) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-71670poj\opencv\modules\imgproc\src\shapedescr.cpp:315: error: (-215:Assertion failed) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function 'cv::contourArea'

My original code is:

cnt = np.array(cnt)
cnt = np.reshape(cnt, (-1, 1, 2))
print('contourArea:', cv2.contourArea(cnt))

I later found out that the reason for the error was that I had defined the outline points incorrectly. The format of the outline points must be int, and the format of the outline points I originally defined was float. Therefore, only the following improvements can be made:

cnt = np.array(cnt, dtype=int)
Leon Brant
  • 11
  • 3
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34769793) – Mark Aug 05 '23 at 09:50
0

I can reproduce this error with cv2.contourArea if the dtype is np.uint8 or float.

import numpy as np
import cv2

print(cv2.__version__)

r = np.array([[156, 109], [81, 109]])

cv2.contourArea(r.astype(np.uint8))  # ERROR
cv2.contourArea(r.astype(np.float))  # ERROR
cv2.contourArea(r.astype(np.int))
cv2.contourArea(r.astype(np.int32))
cv2.contourArea(r.astype(np.int64))

My OpenCV version is '4.6.0'.

Of the above, only dtypes uint8 and float produce this error; the rest work fine:

cv2.error: OpenCV(4.6.0) D:\a\opencv-python\opencv-python\opencv\modules\imgproc\src\shapedescr.cpp:315: error: (-215:Assertion failed) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function 'cv::contourArea'

So remember to cast to a signed int, people!

Michael Currie
  • 13,721
  • 9
  • 42
  • 58