-1

My objective is to crop a bounding box out of an image using opencv's cv2 library. I've found an interesting way of doing it from here, however I am getting an error like

>ValueError: not enough values to unpack (expected 3, got 2)

This is the complete traceback:

Traceback (most recent call last):
  File "text_extraction.py", line 13, in <module>
    image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

And this is my complete code:

import cv2
import numpy as np
import pytesseract

pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files/Tesseract-OCR/tesseract.exe'
im = cv2.imread('detected-image-2.png')
grayimage = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(grayimage, 170, 255, cv2.THRESH_BINARY)
cv2.imshow('mask', mask)
image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
    if cv2.contourArea(contour) < 200:
        continue
    rect = cv2.minAreaRect(contour)
    box = cv2.boxPoints(rect)

    ext_left = tuple(contour[contour[:, :, 0].argmin()][0])
    ext_right = tuple(contour[contour[:, :, 0].argmax()][0])
    ext_top = tuple(contour[contour[:, :, 1].argmin()][0])
    ext_bot = tuple(contour[contour[:, :, 1].argmax()][0])

    roi_corners = np.array([box], dtype=np.int32)

    cv2.polylines(im, roi_corners, 1, (255, 0, 0), 3)
    cv2.imshow('image', im)
    cv2.waitKey(0)

    cropped_image = grayimage[ext_top[1]:ext_bot[1], ext_left[0]:ext_right[0]]
    cv2.imwrite('crop.jpg', cropped_image)

What exactly is wrong in this code? I am relatively new to OpenCV, please help me out.

EDIT: I even tried a way by referring to this answer however the problem still persists.

EDIT-2: upon solving the Value Error, the script was unable to save the cropped image(It was saving the image as it as). Based on statemachines code I changed the code to this:

im = cv2.imread('detected-image-2.png')
grayimage = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(grayimage, 170, 255, cv2.THRESH_BINARY)
cv2.imshow('mask', mask)
cv2.waitKey(0)
contours, hierarchy = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    if cv2.contourArea(contour) < 200:
        continue
    rect = cv2.minAreaRect(contour)
    box = cv2.boxPoints(rect)
    X, Y, W, H = cv2.boundingRect(contour)
    cropped_image = im[Y:Y + H, X:X + W]
    print([X, Y, W, H])
    plt.imshow(cropped_image)
    cv2.imwrite('contour1.png', cropped_image)

However the output is still the same(cropping is not happening).

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
technophile_3
  • 531
  • 6
  • 21
  • 1
    What version of `OpenCV` are you using? Seems to me that you are using ver. `4.+`, in which case `findContours` returns only two values: `contours, hierarchy`. For `OpenCV` ver. `3.+` it returns three values. More info [here](https://docs.opencv.org/4.5.5/d3/dc0/group__imgproc__shape.html#gadf1ad6a0b82947fa1fe3c3d497f260e0). – stateMachine Jan 28 '22 at 07:22
  • the Opencv version is 4.5 removed the image variable from findContours and it worked..however the saved crop.jpg file is not cropped. – technophile_3 Jan 28 '22 at 07:26
  • Calculate the `bounding rectangle` of the `contour`, it will return the top left coordinates and its `height` and `width`, like this: `x, y, w, h = cv2.boundingRect(countour)`. You can use this info to slice (crop) the original image. – stateMachine Jan 28 '22 at 07:39
  • That still didn't help: let me edit the question with the updated code. @stateMachine – technophile_3 Jan 28 '22 at 07:48
  • 1
    you found that answer yet all you could say about it was that you "tried" and "the problem still persists". some detail on your attempt would have helped to help you. -- then going on to "unable to save the cropped image" means you changed the spirit of the question entirely. that should have been a new question. – Christoph Rackwitz Jan 28 '22 at 09:37

1 Answers1

0

Solved it myself after figuring it out where I was making a mistake, in case if someone faces a similar issue, this piece of code would help.

def crop():
    # reading image
    image = cv2.imread("detected-image-1.png")

    # converting to gray scale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # applying canny edge detection
    edged = cv2.Canny(gray, 10, 250)

    # finding contours
    (cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    idx = 0
    for c in cnts:
        x, y, w, h = cv2.boundingRect(c)
        if w > 50 and h > 50:
            idx += 1
            new_img = image[y:y + h, x:x + w]
            # cropping images
            cv2.imwrite("cropped/" + str(idx) + '.png', new_img)
    print('Objects Cropped Successfully!')
technophile_3
  • 531
  • 6
  • 21