Reputation: 655
I have a NumPy array contours
that I got from cv2.findContours
and flattened using contours = np.concatenate(contours, axis = 0)
. It stores coordinates of contours of objects from an image. However, I want to delete coordinates whose either X or Y is lower than, let's say, 100, or bigger than 1000. I first tried using contours = np.delete(contours, 0)
and contours = np.delete(contours[0], 0)
to just delete any item, but I kept getting this error:
IndexError: invalid index to scalar variable.
How to delete such pairs of values?
print(type(contours))
→ <class 'numpy.ndarray'>
print(contours[0])
→ [[2834 4562]]
print(type(contours[0]))
→ <class 'numpy.ndarray'>
print(contours[0][0])
→ [2834 4562]
print(type(contours[0][0]))
<class 'numpy.ndarray'>
Also, I don't want to concatenate/flatten the list any further, because it's exactly in the form I need it to send to cv2.convexHull(contours)
.
Here's a minimal working sample of my code:
import cv2 # library for processing images
import numpy as np # numerical calculcations for Python
img = cv2.imread("img.png")
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_, img_thr = cv2.threshold(img_gray,0,255,cv2.THRESH_OTSU)
img_rev = cv2.bitwise_not(img_thr)
img_cnt, contours, hierarchy = cv2.findContours(img_rev, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = np.concatenate(contours, axis = 0)
hull = cv2.convexHull(contours)
rect = cv2.minAreaRect(np.int0(hull))
box = cv2.boxPoints(rect)
box = np.int0(box)
img_cnt = cv2.drawContours(img, contours, -1, (0,255,0), 3)
img_cnt = cv2.drawContours(img, [box], -1, (0,0,255), 5)
cv2.imwrite("img_out.png", img_cnt)
Here is a sample input image, here is my output image. I want to ignore outlying "noise" for text selection. Assume I cannot use further noise reduction.
Upvotes: 2
Views: 1209
Reputation: 18638
It seems that contours.shape is (N,1,2) . in this case,
contours[((contours>100)&(contours<1000)).all(axis=(1,2))]
will work.
by example:
In [106]: contours=randint(0,1100,(10,1,2))
[[[ 803 772]]
[[ 210 490]]
[[ 433 76]]
[[ 347 88]]
[[ 763 747]]
[[ 678 200]]
[[ 816 444]]
[[ 528 817]]
[[ 140 440]]
[[1019 654]]]
In [108]: valid = ((contours>100)&(contours<1000)).all(axis=(1,2))
Out[108]: array([ True, True, False, False, True, True,
True, True, True, False], dtype=bool)
In [111]: contours[valid]
Out[111]:
array([[[803, 772]],
[[210, 490]],
[[763, 747]],
[[678, 200]],
[[816, 444]],
[[528, 817]],
[[140, 440]]])
If you want different clips on X and Y, then you can use
(contours>[xmin,ymin])&(contours<[xmax,ymax])
instead.
Upvotes: 2