1

I can't extract the detected regions by MSER in this image:

img

What I want to do is to save the green bounded areas. My actual code is this:

import cv2
import numpy as np

mser = cv2.MSER_create()
img = cv2.imread('C:\\Users\\Link\\img.tif')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
regions, _ = mser.detectRegions(gray)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(vis, hulls, 1, (0, 255, 0))

mask = np.zeros((img.shape[0], img.shape[1], 1), dtype=np.uint8)
mask = cv2.dilate(mask, np.ones((150, 150), np.uint8))
for contour in hulls:
    cv2.drawContours(mask, [contour], -1, (255, 255, 255), -1)

    text_only = cv2.bitwise_and(img, img, mask=mask)


cv2.imshow('img', vis)
cv2.waitKey(0)
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.imshow('text', text_only)
cv2.waitKey(0)

Expected result should be a ROI like image.

out

Source image:

src

lucians
  • 2,239
  • 5
  • 36
  • 64
  • How do you want to 'save' them? One image per region, no matter the size? Extracting sub-arrays of those regions? Could you clarify what's the expected result? – GPhilo Dec 01 '17 at 14:42
  • @GPhilo edited the question – lucians Dec 01 '17 at 14:48
  • Have a look here: https://www.bytefish.de/blog/extracting_contours_with_opencv/ – lorenzo Dec 06 '17 at 15:42
  • Was reading it right now...do you think it will work with images which contains numbers so small ? – lucians Dec 06 '17 at 15:43
  • Canny filter (or blur+threshold) could make them big enough for this. Otherwise use findContours or MSER to find big white patches, like you did above, and use those as your mask. But as GPhilo said you can only save rectangular images, using a rounded contour may be useful only to leave out some noise. – lorenzo Dec 06 '17 at 15:49
  • Alright, so it's official that I can't save MSER shapes with content inside.. – lucians Dec 06 '17 at 15:52
  • @lorenzo found it [https://stackoverflow.com/questions/15341538/numpy-opencv-2-how-do-i-crop-non-rectangular-region](https://stackoverflow.com/questions/15341538/numpy-opencv-2-how-do-i-crop-non-rectangular-region) – lucians Dec 28 '17 at 21:40

3 Answers3

4

detectRegions also returns bounding boxes:

regions, boundingBoxes = mser.detectRegions(gray)

for box in boundingBoxes:
        x, y, w, h = box;
        cv2.rectangle(vis, (x, y), (x+w, y+h), (0, 255, 0), 1)

This draws green rectangles, or save them as mentioned in GPhilo's answer.

Manstie
  • 333
  • 1
  • 5
  • 13
2

Just get the bounding box for each contour, use that as a ROI to extract the area and save it out:

for i, contour in enumerate(hulls):
    x,y,w,h = cv2.boundingRect(contour)
    cv2.imwrite('{}.png'.format(i), img[y:y+h,x:x+w])
GPhilo
  • 18,519
  • 9
  • 63
  • 89
  • Did you tried it ? I am asking because it doesn't work. I mean, it save "something" (debris for most the files) but it's not ok. I like, instead, the way to count the files with formatting strings. – lucians Dec 01 '17 at 15:00
  • Can't try it because I don't have sample data to run it on, it is possible I swapped x and y coordinates in `img[...]`. Can you please try running it with `img[y:y+h, x:x+w]` instead and see if that fixes it? – GPhilo Dec 01 '17 at 15:01
  • Yes, the coordinates was swapped. Now it works. Just to know, the code above is standard to saving bounding boxes (I mean x,y,w,h ...) ? – lucians Dec 01 '17 at 15:04
  • Thanks, fixed the answer with the right coord order. In python, OpenCV's `boundingRect` returns a 4-tuple `(x,y,w,h)`, which I extracted directly in the 4 values because I needed them for the array indexing. Ideally, if you need to store the bounding box, you'd keep the 4-tuple as it was. – GPhilo Dec 01 '17 at 15:06
  • Can you show me also how to order them ? They are being saved "wildly". – lucians Dec 01 '17 at 15:46
  • They are being saved in the order they are in `hulls`, so if you want them to be sorted in some way you need to sort that list – GPhilo Dec 01 '17 at 15:50
  • EDIT: did it...was simple. – lucians Dec 01 '17 at 15:56
  • sorry if I bother you, but I am curios about one thing: the code you suggested create a bounding box around detected areas and then it is being saved, box by box. But what if I want to save the shape MSER detect ? Not to create a box around each char but to extract it the exact shape. Do you know how to do ? Thanks – lucians Dec 04 '17 at 10:15
  • 1
    You can only save rectangular images, that's why I get the bounding box. If you want the shape, what you can do is save the data from the multiplication of the input image and the mask (i.e., the third image in your question), that way you'll have a black outline that you can remove afterwards in your processing – GPhilo Dec 04 '17 at 10:19
  • But which is the variable to save here as mask ? I tried to imwrite text-only but it save me all the image, not a single ROI.. – lucians Dec 04 '17 at 10:29
  • found it [https://stackoverflow.com/questions/15341538/numpy-opencv-2-how-do-i-crop-non-rectangular-region](https://stackoverflow.com/questions/15341538/numpy-opencv-2-how-do-i-crop-non-rectangular-region) – lucians Dec 28 '17 at 21:40
1

Hey found a cleaner way to get the bounding boxes

regions, _ = mser.detectRegions(roi_gray)

bounding_boxes = [cv2.boundingRect(p.reshape(-1, 1, 2)) for p in regions]
John M
  • 59
  • 1
  • 3
  • 1
    As Mansite already mentioned, detectRegions actually returns these bounding boxes in the second returned argument (which you denote as _) – feature_engineer Dec 21 '20 at 05:52