TypeError: Expected Ptr<cv::UMat> for argument 'array' - image

The following is the code I have written: I am getting the following error while executing this code-
**
x,y,w,h = cv2.boundingRect(contours) TypeError: Expected Ptr<cv::UMat>
for argument 'array'
I am trying to make the rectangle outside my contours
**
from cv2 import cv2
import numpy as np
cam = cv2.VideoCapture(0)
kernel_open = np.ones((7,7), np.uint8)
kernel_close = np.ones((15,15), np.uint8)
while True:
ret, frame = cam.read()
frame = cv2.resize(frame, (340,220))
# Our image is in BGR format. We need to conver it into HSV
imgHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Now we'll apply masking to capture green colour
lower_lim = np.array([33, 80, 40])
upper_lim = np.array([102, 255, 255])
mask = cv2.inRange(imgHSV, lower_lim, upper_lim)
# As we are getting noises so we'll remove the noise by morphological transformation- Opening and Closing
mask_open = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_open)
mask_close = cv2.morphologyEx(mask_open, cv2.MORPH_CLOSE, kernel_close)
# Till now we have identified the colour of the image we want
# Now we'll make boundary or contours around our required colour image
contours, hierarchy = cv2.findContours(mask_close.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(frame, contours, -1, (0,0,255), 3)
# Now we'll draw rectangles
for i in range(len(contours)):
x,y,w,h = cv2.boundingRect(contours)
cv2.rectangle(frame, (x,y), (x+w, y+h), (255,0,0), 3)
cv2.imshow('Original Image', frame)
cv2.imshow('Mask Closed Image', mask_close)
if cv2.waitKey(1) == 27:
break
cam.release()
cv2.destroyAllWindows()

Cast your mask_close array as an unsigned 8-bit integer array
cv2.findContours((mask_close.astype(np.uint8).copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

you can try
we need to make it mask_close= mask_close[0]
replace your code
contours, hierarchy = cv2.findContours(mask_close.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
with
mask_close= mask_close[0] contours, hierarchy = cv2.findContours(mask_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

Replace the line:
contours, hierarchy = cv2.findContours(mask_close.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
with the following lines:
contours, hierarchy = cv2.findContours(mask_close.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2:]
Actually, in a particular version of OpenCV, cv2.findContours() function returns 3 values instead of 2. The three values being: image, contours, hierarchy in the same order.
I think you are using that version only that is why this is happening.

Related

batch crop quad images with diffenrent sizes to a circle

I have lots of images of planets in differing sizes like
They are all positioned exactly in the middle of the square images but with different height.
Now I want to crop them and make the black border transparent. I tried with convert (ImageMagick 6.9.10-23) like this:
for i in planet_*.jpg; do
nr=$(echo ${i/planet_/}|sed s/.jpg//g|xargs)
convert $i -fuzz 1% -transparent black trans/planet_${nr}.png
done
But this leaves some artifacts like:
Is there a command to crop all images in a circle, so the planet is untouched? (It mustn't be imagemagick).
I could also imagine a solution where I would use a larger -fuzz value and then fill all transparent pixels in the inner planet circle with black.
Those are all planets, I want to convert: download zip
Here is one way using Python Opencv from the minEclosingCircle.
Input:
import cv2
import numpy as np
import skimage.exposure
# read image
img = cv2.imread('planet.jpg')
h, w, c = img.shape
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
# get contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# get enclosing circle
center, radius = cv2.minEnclosingCircle(big_contour)
cx = int(round(center[0]))
cy = int(round(center[1]))
rr = int(round(radius))
# draw outline circle over input
circle = img.copy()
cv2.circle(circle, (cx,cy), rr, (0, 0, 255), 1)
# draw white filled circle on black background as mask
mask = np.full((h,w), 0, dtype=np.uint8)
cv2.circle(mask, (cx,cy), rr, 255, -1)
# antialias
blur = cv2.GaussianBlur(mask, (0,0), sigmaX=2, sigmaY=2, borderType = cv2.BORDER_DEFAULT)
mask = skimage.exposure.rescale_intensity(blur, in_range=(127,255), out_range=(0,255))
# put mask into alpha channel to make outside transparent
imgT = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
imgT[:,:,3] = mask
# crop the image
ulx = int(cx-rr+0.5)
uly = int(cy-rr+0.5)
brx = int(cx+rr+0.5)
bry = int(cy+rr+0.5)
print(ulx,brx,uly,bry)
crop = imgT[uly:bry+1, ulx:brx+1]
# write result to disk
cv2.imwrite("planet_thresh.jpg", thresh)
cv2.imwrite("planet_circle.jpg", circle)
cv2.imwrite("planet_mask.jpg", mask)
cv2.imwrite("planet_transparent.png", imgT)
cv2.imwrite("planet_crop.png", crop)
# display it
cv2.imshow("thresh", thresh)
cv2.imshow("circle", circle)
cv2.imshow("mask", mask)
cv2.waitKey(0)
Threshold image:
Circle on input:
Mask image:
Transparent image:
Cropped transparent image:
packages to install
sudo apt install python3-opencv python3-sklearn python3-skimage

Remove only black dot in the image using opencv

I am posting to understand that is that possible to remove only black dot in the image.
Here are two methods:
Method #1: Contour filtering
We convert the image to grayscale, Otsu's threshold for a binary image, then find contours and filter using a minimum threshold area. We remove the black dots by drawing filling in the contours to effectively erase the dots
import cv2
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
if cv2.contourArea(c) < 10:
cv2.drawContours(thresh, [c], -1, (0,0,0), -1)
result = 255 - thresh
cv2.imshow('result', result)
cv2.waitKey()
Method #2: Morphological operations
Similarly, we convert to grayscale then Otsu's threshold. From here we create a kernel and perform morph open
import cv2
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
opening = 255 - cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
cv2.imshow('opening', opening)
cv2.waitKey()

How Can I only keep text with specific color from image via opencv and python?

I have some invoice image with some text overlapping, which make some trouble for later processing, and what I only is the text in black. some I want to remove the text which is in other colors.
is there any way to achieve this?
the image is attached as example.
I have tried to solve it with opencv, but i still can't solve this:
import numpy as np import cv2
img = cv2.imread('11.png')
lower = np.array([150,150,150])
upper = np.array([200,200,200])
mask = cv2.inRange(img, lower, upper)
res = cv2.bitwise_and(img, img, mask=mask)
cv2.imwrite('22.png',res)
[image with multiple color][1]
[1]: https://i.stack.imgur.com/nWQrV.pngstrong text
The text is darker and less saturated. And as suggested as #J.D. the HSV color space is good. But his range is wrong.
In OpenCV, the H ranges in [0, 180], while the S/V ranges in [0, 255]
Here is a colormap I made in the last year, I think it's helpful.
(1) Use cv2.inRange
(2) Just threshold the V(HSV) channel:
th, threshed = cv2.threshold(v, 150, 255, cv2.THRESH_BINARY_INV)
(3) Just threshold the S(HSV) channel:
th, threshed2 = cv2.threshold(s, 30, 255, cv2.THRESH_BINARY_INV)
The result:
The demo code:
# 2018/12/30 22:21
# 2018/12/30 23:25
import cv2
img = cv2.imread("test.png")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
mask = cv2.inRange(hsv, (0,0,0), (180, 50, 130))
dst1 = cv2.bitwise_and(img, img, mask=mask)
th, threshed = cv2.threshold(v, 150, 255, cv2.THRESH_BINARY_INV)
dst2 = cv2.bitwise_and(img, img, mask=threshed)
th, threshed2 = cv2.threshold(s, 30, 255, cv2.THRESH_BINARY_INV)
dst3 = cv2.bitwise_and(img, img, mask=threshed2)
cv2.imwrite("dst1.png", dst1)
cv2.imwrite("dst2.png", dst2)
cv2.imwrite("dst3.png", dst3)
How to detect colored patches in an image using OpenCV?
How to define a threshold value to detect only green colour objects in an image :Opencv
Converting to the HSV colorspace makes selecting colors easier.
The code below does what you want.
Result:
import numpy as np
import cv2
kernel = np.ones((2,2),np.uint8)
# load image
img = cv2.imread("image.png")
# Convert BGR to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of black color in HSV
lower_val = np.array([0,0,0])
upper_val = np.array([179,100,130])
# Threshold the HSV image to get only black colors
mask = cv2.inRange(hsv, lower_val, upper_val)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(img,img, mask= mask)
# invert the mask to get black letters on white background
res2 = cv2.bitwise_not(mask)
# display image
cv2.imshow("img", res)
cv2.imshow("img2", res2)
cv2.waitKey(0)
cv2.destroyAllWindows()
To change the level of black selected, tweak from the upper_val, the value currently set at 130. Higher = allow lighter shades (it's called the Value). Also the value currently at 100: lower = allow less color (actually: saturation).
Read more about the HSV colorspace here.
I always find the image below very helpfull. The bottom 'disc' is all black. As you move up in Value, lighter pixels are also selected. The pixels with low saturation stay shades of gray until white (the center), the pixels with high saturation get colored(the edge).That's why you tweak those values.
Edit: As #Silencer pointed out, my range was off. Fixed it.

How to color the mask image obtained out of a polygon

I am getting a mask out of a polygon and below is the image. Now I see that there is a white boundary but I want not just the boundary but inside boundary as white too.
Here is my code:
sar_polygon = Image.new('L', (int(range_samples), int(azimuth_lines)), 0)
draw = ImageDraw.Draw(sar_polygon)
for vertex in range(len(sar_ver)):
st = sar_ver[vertex]
try:
end = sar_ver[vertex + 1]
except IndexError:
end = sar_ver[0]
draw.line((st[0], st[1], end[0], end[1]), fill=1)
sar_polygon.save('polygon.jpg', 'JPEG')
You are currently drawing lines along the edges. You are interested in the polygon method, or perhaps the rectangle method - http://pillow.readthedocs.io/en/5.2.x/reference/ImageDraw.html#PIL.ImageDraw.PIL.ImageDraw.ImageDraw.polygon.
from PIL import Image, ImageDraw
sar_polygon = Image.new('RGB', (500, 500))
draw = ImageDraw.Draw(sar_polygon)
sar_ver = ((100,100),(200,100),(200,200),(100,200))
draw.polygon(sar_ver, fill='#f00')
sar_polygon.save('polygon.jpg', 'JPEG')

Detecting rectangle in image

I would like to ask if somebody could help me with rectangle detection in image.
I've tried contour detection, but results are not sufficient.
I'd be thankful for any ideas.
I have tried this:
EDIT 1
# loading image
im = cv2.imread('b.jpeg',cv2.IMREAD_GRAYSCALE)
# equalization
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
im = clahe.apply(im)
# bluring image
im = cv2.GaussianBlur(im,(5,5),0)
# edge detection
edges = cv2.Canny(im,100,200)
cv2.imshow('Canny',edges)
cv2.moveWindow('Canny',0,0)
cv2.waitKey(0)
cv2.destroyAllWindows()
# contour extraction
ret,thresh = cv2.threshold(edges,50,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(im, contours, -1, (0,255,0), 3)
cv2.imshow('Contour',im)
cv2.moveWindow('Contour',0,0)
cv2.waitKey(0)
cv2.destroyAllWindows()
cntrRect = []
for i in contours:
approx = cv2.approxPolyDP(i,0.1*cv2.arcLength(i,True),True)
x,y,w,h = cv2.boundingRect(approx)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
#peri = cv2.arcLength(i,True)
epsilon = 0.1*cv2.arcLength(i,True)
#0.02*peri
approx = cv2.approxPolyDP(i,epsilon,True)
if len(approx) == 4:
cntrRect.append(approx)
cv2.imshow('Contour2',im)
cv2.moveWindow('Contour2',0,0)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.drawContours(im, cntrRect, -1, (255,0,0), 3)
cv2.imshow('Contour3',im)
cv2.moveWindow('Contour3',0,0)
cv2.waitKey(0)
cv2.destroyAllWindows()

Resources