Trying to find the circles and rectangle (or square) in an irregular object using contours,edge detection but not getting the output properly.
I tried changing values of canny values and epsilon(contour approx) but was not able to detect,
Another difficulty iam facing is lot hand written character are there in the metal object so my code is detecting that also as a shape
Can anyone please help me on detecting this required shape on this object using opencv-python.
Metal object
import imutils
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread('part1.jpg')
#image = cv2.imread('C:\Python27\plates\plates2.1.jpg')#$episolon==0.04,len=5,6
#image = cv2.imread('C:\Python27\plates\plates4.jpg')
#image = cv2.imread('C:\Python27\plates\plates1.jpg')
#image = cv2.imread('C:\Python27\plates\plates3.jpg')#episilon=0.0370,len=5
#image = cv2.imread('C:\Python27\plates\plates5.jpg') #change the episilon to 0.01
#image = cv2.imread('C:\Python27\plates\plates6.jpg')#not working properly
cv2.namedWindow('Image')
#for angle in xrange(0, 360, 90):
# rotate the image and display it
#image = imutils.rotate(image, angle=angle)
#gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
#blurred = cv2.GaussianBlur(gray, (5, 5), 0)
#edges=cv2.Canny(image,200,650)#plates3.jpg,plates1.jpg,plates5.jpg,
#edges=cv2.Canny(image,200,500)#plates4.jpg
#edges=cv2.Canny(image,200,589)#plates2.1.jpg
#edges=cv2.Canny(image,100,450)
edges=cv2.Canny(image,300,589)
kernel = np.ones((5,5),np.uint8)
#thresh = cv2.erode(edges,kernel,iterations = 1)
#thresh = cv2.dilate(edges,kernel,iterations = 1)
#thresh = cv2.morphologyEx(edges, cv2.MORPH_OPEN, kernel)
thresh = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
sd = ShapeDetector()
print len(cnts)
for c in cnts:
shape = "unidentified"
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.0373* peri, True)
if len(approx) == 4:
(x, y, w, h) = cv2.boundingRect(approx)
#ar = w / float(h)
#shape = "slots" if ar >= 0.95 and ar <= 1.05 else "slots"
shape="slots"
#cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image,[box],0,(0,0,255),2)
#cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
cv2.putText(image, shape, (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255, 255, 255), 4)
elif len(approx)==2:
shape="nothing"
(x,y),radius = cv2.minEnclosingCircle(c)
center = (int(x),int(y))
radius = int(radius)
#cv2.circle(image,center,radius,(0,255,0),2)
#cv2.putText(image, shape, (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255, 255, 255), 4)
elif len(approx)==5:
shape="nothing"
elif len(approx)==3:
shape="nothing"
elif len(approx)==6:
shape="nothing"
else:
shape = "c"+str(len(approx))
(x,y),radius = cv2.minEnclosingCircle(c)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(image,center,radius,(0,255,0),2)
cv2.putText(image, shape, (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255, 255, 255), 2)
cv2.imshow("Image",image)
cv2.imshow("edges", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
Use binarization. You will get blobs that you can discriminate by size, location and other geometric criteria.
Related
This is my full code.
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
width = cap.get(3) # float
height = cap.get(4) # float
print (width, height)
while (1):
_, img = cap.read()
if _ is True:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
else:
continue
# blue color
blue_lower = np.array([86,0,90], np.uint8)
blue_upper = np.array([163, 64, 145], np.uint8)
blue = cv2.inRange(hsv, blue_lower, blue_upper)
kernal = np.ones((9, 9), "uint8")
blue = cv2.dilate(blue, kernal)
res_blue = cv2.bitwise_and(img, img, mask=blue)
# Tracking blue
(_, contours, hierarchy) = cv2.findContours(blue, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
if (area > 2000):
print (area)
x, y, w, h = cv2.boundingRect(contour)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(img, "Blue Colour", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0))
# cv2.putText(img, "Blue Colour", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0))
cv2.imshow("Color Tracking", img)
if cv2.waitKey(10) & 0xFF == ord('q'):
cap.release()
cv2.destroyAllWindows()
break
I would like to mesh all rectangles as these pictures.
you can see the mesh of the contour next to them.
In my case, I would like to mesh rectangles themselves.
This picture is taken from this video
I am trying to detect foreign substances in a round circle using opencv.
However, if the threshold is increased, the area around the circle is distorted, and if the threshold is decreased, foreign matter cannot be detected. Is there a way to detect foreign matter well while maintaining the circle?
import cv2
import cv2 as cv
import numpy as np
def roiSetting():
img = cv2.imread('img.jpg')
x = 100; y = 10;
w = 700; h = 600;
img_roi = img[400:1250,600:1450] #[colStart:colEnd, rowStart:rowEnd]
cv2.imwrite("3_roi_img.jpg", img_roi)
return img_roi
def imgCvt():
print("imgCvt in")
roi_img = roiSetting()
bgr_img = cv2.cvtColor(roi_img,cv2.COLOR_RGB2BGR) #RGB->BGR convert
bila_img = cv2.bilateralFilter(bgr_img,9,100,100) #bilaterafilter apply
r,g,b=cv2.split(bila_img) #split
merge_img=cv2.merge((r,g,b)) #merge
gray_img = cv2.cvtColor(merge_img,cv2.COLOR_RGB2GRAY) #RGB->GRAY convert
ret,thresh_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY) #threshold apply
equalize_img = cv2.equalizeHist(thresh_img) #Histogram equlization
canny_img = cv2.Canny(equalize_img,250,255) #Canny edge
kernel = np.ones((2,2), np.uint8)
dilate_img = cv2.dilate(canny_img, kernel, iterations = 1) # img dilate
new, contours, hierarchy = cv2.findContours(dilate_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10] #sorting
print(contours)
c = contours[0]
mask = np.zeros(roi_img.shape,np.uint8) #mask create(roi_img.shape)
cont_image = cv2.drawContours(mask, [c], -1, (255, 255, 255), -1) #background remove
con_gray_img = cv2.cvtColor(cont_image, cv2.COLOR_BGR2GRAY)
ret, thresh1 = cv2.threshold(con_gray_img, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)
last_img = cv2.bitwise_and(roi_img, roi_img, mask = thresh1)
kernel = np.ones((3,3), np.uint8)
src = cv2.erode(last_img, kernel, iterations = 2)
gray = cv2.cvtColor(src, cv2.COLOR_RGB2GRAY)
rt1, dst1 = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)
rt1, dst2 = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
_, contour1, _ = cv.findContours(dst2, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
for cnt in contour1:
cv2.drawContours(roi_img, [cnt], 0, (255, 0, 0), 2, cv2.LINE_8)
cv2.imshow('cont_roi.jpg', roi_img)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
imgCvt()
I'm working on a project that requires me to detect a red rectangle in real time. so far I've managed to get the colour and shape detected together but it can't differentiate between other objects that are red.
How might I go about doing this?
import cv2
import numpy as np
def nothing():
pass
cap = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_COMPLEX
while True:
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Red color
low_red = np.array([175, 50, 20])
high_red = np.array([180, 255, 255])
mask1 = cv2.inRange(hsv, low_red, high_red)
kernel = np.ones((5, 5), np.uint8)
mask2 = cv2.erode(mask1, kernel)
red = cv2.bitwise_and(frame, frame, mask=mask2)
contours, _ = cv2.findContours(mask2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
hull = cv2.convexHull(cnt)
x = approx.ravel()[0]
y = approx.ravel()[1]
if area > 400:
cv2.drawContours(frame, [approx], 0, (0, 0, 0), 5)
if len(approx) == 4:
cv2.putText(frame, "Rectangle", (x, y), font, 1, (0, 0, 0))
edges = cv2.Canny(frame, 100, 200)
_, threshold_binary = cv2.threshold(frame, 128, 255, cv2.THRESH_BINARY)
_, threshold_binary_inv = cv2.threshold(frame, 128, 255, cv2.THRESH_BINARY_INV)
_, threshold_trunc = cv2.threshold(frame, 128, 255, cv2.THRESH_TRUNC)
_, threshold_to_zero = cv2.threshold(frame, 12, 255, cv2.THRESH_TOZERO)
cv2.imshow("Frame", frame)
cv2.imshow('edges', edges)
cv2.imshow('red', red)
cv2.imshow("mask", mask1)
key = cv2.waitKey(1)
if key == 27:
cap.release()
cv2.destroyAllWindows()
break
Output image:
I am pretty new to Python and OpenCV. I have some screenshots (attached one sample for reference) for which I want to identify the forecolor and backcolor of the Text. I will be using this colors for calculating the color contrast ratio for the text. Using pytesseract, I am able to identify the words and drawn bounding rectangles to the text. Can anyone guide me how can I detect the forecolor and backcolor of the text? Below is the code which I did so far.
import cv2
import pytesseract
import numpy as np
pytesseract.pytesseract.tesseract_cmd = 'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'
imgOriginal = cv2.imread('3.png')
gray = cv2.cvtColor(imgOriginal, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
img = cv2.GaussianBlur(thresh, (3,3), 0)
cv2.imshow("Filtered",img)
### Detecting words
hImg,wImg,_ = imgOriginal.shape
boxes = pytesseract.image_to_data(img, config='--psm 6') #list
for i,b in enumerate(boxes.splitlines()):
if i!=0: #no need to extract the first row since it is the header
b=b.split()
if len(b)==12: #12th item is the word
x, y, w, h = int(b[6]), int(b[7]), int(b[8]), int(b[9])
cv2.rectangle(imgOriginal, (x, y), (x+w, y+h), (0, 0, 255), 1)
cv2.imshow('Image',imgOriginal)
k = cv2.waitKey(0)
if k==ord('q'):
cv2.destroyAllWindows()
In case if you are still looking for an answer.
imgOriginal = cv2.imread('windows.png')
image = imgOriginal.copy()
image_1 = imgOriginal.copy()
gray = cv2.cvtColor(imgOriginal, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Removing the horizantal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,1))
detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(image, [c], -1, (255,255,255), 2)
# Removing the vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,7))
detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(image, [c], -1, (255,255,255), 2)
gray_no_lines = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
otsu = cv2.threshold(gray_no_lines, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
### Detecting words
boxes = pytesseract.image_to_data(otsu, config='--psm 6') #list
xs = []
ys = []
ws = []
hs = []
words = []
for i,b in enumerate(boxes.splitlines()):
if i!=0: #no need to extract the first row since it is the header
b=b.split()
if len(b)==12: #12th item is the word
if b[11] != -1:
x, y, w, h = int(b[6]), int(b[7]), int(b[8]), int(b[9])
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 0, 255), 1)
xs.append(x)
ys.append(y)
ws.append(w)
hs.append(h)
words.append(b[11])
text_colors = []
bg_colors = []
for j in range(len(words)):
x,y,w,h = xs[j],ys[j],ws[j],hs[j]
roi_otsu = otsu[y:y+h,x:x+w]
roi_image = image_1[y:y+h,x:x+w]
black_coords = np.column_stack(np.where(roi_otsu == 0))
white_coords = np.column_stack(np.where(roi_otsu == 255))
blues_text = []
greens_text = []
reds_text = []
blues_bg = []
greens_bg = []
reds_bg = []
for i in range(len(black_coords)):
blue_t = roi_image.item(black_coords[i][0],black_coords[i][1],0)
green_t = roi_image.item(black_coords[i][0],black_coords[i][1],1)
red_t = roi_image.item(black_coords[i][0],black_coords[i][1],2)
blues_text.append(blue_t)
greens_text.append(green_t)
reds_text.append(red_t)
color_t = (int(np.mean(blues_text)),int(np.mean(greens_text)),int(np.mean(reds_text)))
for i in range(len(white_coords)):
blue_bg = roi_image.item(white_coords[i][0],white_coords[i][1],0)
green_bg = roi_image.item(white_coords[i][0],white_coords[i][1],1)
red_bg = roi_image.item(white_coords[i][0],white_coords[i][1],2)
blues_bg.append(blue_bg)
greens_bg.append(green_bg)
reds_bg.append(red_bg)
color_bg = (int(np.mean(blues_bg)),int(np.mean(greens_bg)),int(np.mean(reds_bg)))
text_colors.append(color_t)
bg_colors.append(color_bg)
print(text_colors)
print(bg_colors)
# print(len(text_colors),len(bg_colors))
I have removed the horizontal and vertical lines for better results. binarised the image and collected the coordinates of each text region. sliced the region of interests and collected the pixel coordinated of text and background(from the binarised sliced region). collected the pixel values of those coordinates from the color-sliced region. Took the average of each color and appended the color to a final list.
Hope this solves your problem. Please correct me if I am wrong.
could you help me with better paper warping? Right now it looks like this and as you can see it's really bad as many cells are 50% black 50% white. Here's my code if it helps:
image = cv2.imread("image2.jpg")
ratio = image.shape[0] / 500.0
orig = image.copy()
image = imutils.resize(image, height = 500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ret,warped = cv2.threshold(warped,160,255,cv2.THRESH_BINARY)
Below is the code adding the skew detection part to your code:
import numpy as np
import cv2
from imutils.perspective import four_point_transform
import imutils
image = cv2.imread("image2.jpg")
ratio = image.shape[0] / 500.0
orig = image.copy()
image = imutils.resize(image, height = 500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
warped = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
coords = np.column_stack(np.where(warped > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
angle = -(90 + angle)
else:
angle = -angle
print(angle)
(h, w) = warped.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(warped, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
cv2.imshow('Corrected', imutils.resize(rotated, height = 650))
cv2.waitKey(0)
It didn't identify any skew in the warped image. But sometimes it happens that after warping you need to check if there is any skew resulting from not so accurate warping.