OpenCv Get edge distance to circle center - opencv

A bit off an intro, i need to make a visual aid to align sheets against fixed points.
My setup has 3 points, a sheetmetal plate needs to be positioned against these points using a forklift.
Its a gentle task, we cant use brut force to align the sheet, so i want to install camera's to help them align there sheetmetal plate.
Code so far:
import sys
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
val = 50
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (5,5), 0)
rows = gray.shape[0]
circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows / 8,
param1=100, param2=30,
minRadius=1, maxRadius=30)
edges = cv.Canny(gray,val,val*3,apertureSize = 3)
lines = cv.HoughLines(edges,1.2,np.pi/180,200)
font = cv.FONT_HERSHEY_SIMPLEX
color = (255, 255, 255)
thickness = 2
index = 1
if len(circles[0]) > 2 :
circles = np.uint16(np.floor(circles))
circles2=sorted(circles[0],key=lambda x:x[0],reverse=False)
print (circles2)
for i in circles2:
center = (i[0], i[1])
cv.circle(frame, center, 1, (0, 255, 0), 3)
text = str(index) +' ' + str(i[0]) +' ' + str(i[1])
cv.putText(frame, text, center, font, 1, color, thickness, cv.LINE_AA)
index += 1
cv.imshow("detected circles", frame)
cv.imshow("detected edges", edges)
if cv.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()
So the points are found, somehow i need to find the first 255 value in edges right 'above' the 2nd and 3th point, and the last 255 value next to the first point
i'm struggling too slice? the array, find the value 255, returns its index, so i can calculate the distance between point and plate.
any ideas on how to get the distance between?
Thank you in advance

I got it.
the code:
import sys
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
val = 50
singleprint = 0
# Dots per millimeter
dpmm = 2
def distance(circle):
# Calculating the distance np.where(array[row, column])
p = 0
if axis == 1:
p = np.where(edges[:,circle[0]] == 255)[0][0]
return (circle[1] - p - circle[2])/dpmm
else:
p = np.where(edges[circle[1],:] == 255)[0][-1]
return (p - circle[0] - circle[2])/dpmm
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (5,5), 0)
rows = gray.shape[0]
circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows / 8,
param1=100, param2=30,
minRadius=1, maxRadius=30)
edges = cv.Canny(gray,val,val*3,apertureSize = 3)
lines = cv.HoughLines(edges,1.2,np.pi/180,200)
# Text property's
font = cv.FONT_HERSHEY_SIMPLEX
color = (255, 255, 255)
thickness = 2
index = 1
axis = 0
if len(circles[0]) > 2 :
circles = np.uint16(np.floor(circles))
circles2=sorted(circles[0],key=lambda x:x[0],reverse=False)
for i in circles2:
center = (i[0], i[1])
cv.circle(frame, center, 1, (0, 255, 0), 3)
text = str(distance(i))
cv.putText(frame, text, center, font, 1, color, thickness, cv.LINE_AA)
index += 1
axis = 1
cv.imshow("detected circles", frame)
if cv.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv.destroyAllWindows()
Key was learning to use Numpy in a specific row or column
np.where(edges[:,circle[0]] == 255)[0][0]
resource: https://youtu.be/GB9ByFAIAH4?t=1103
Hope this helps others.
Thanks all

Related

Why the output of Dense Optical Flow in OpenCV is not continuous?

I want to track whether worker throw garbage into the truck manually in the video.
Q1: Is Dense Optical Flow in OpenCV a good solution for me?
Q2: I tried to code a sample. But why the flow image is not continuous?
frame 41 and 43 is good , but frame 42 is black
Q3: Can I spy on the color change in a small area to track if garbage through ?
small area like this:
here is my code. you can run my code and video in my github repository
https://github.com/Pinocchio2018/QuestionHelper/blob/main/openCV_related/dence_optical_flow_problem/test.py
import numpy as np
import cv2 as cv
def put_frame_no(image, frame_no):
# font
font = cv.FONT_HERSHEY_SIMPLEX
# org
org = (50, 450)
# fontScale
font_scale = 2
# Blue color in BGR
color = (0, 0, 255)
# Line thickness of 2 px
thickness = 2
# Using cv2.putText() method
image = cv.putText(image, "frame no: " + str(frame_no), org, font,
font_scale, color, thickness, cv.LINE_AA)
return image
cap = cv.VideoCapture(cv.samples.findFile("0116-sample4-edited-short-throw.mp4"))
ret, frame1 = cap.read()
prv_frame = cv.cvtColor(frame1, cv.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[..., 1] = 255
cv.namedWindow("flow image", cv.WINDOW_NORMAL)
cv.resizeWindow("flow image", 800, 600)
frame_no = 0
while 1:
ret, origin_img = cap.read()
if not ret:
print('No frames grabbed!')
break
next_frame = cv.cvtColor(origin_img, cv.COLOR_BGR2GRAY)
flow = cv.calcOpticalFlowFarneback(prv_frame, next_frame, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, ang = cv.cartToPolar(flow[..., 0], flow[..., 1])
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 2] = cv.normalize(mag, None, 0, 255, cv.NORM_MINMAX)
flow_image = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)
flow_image = put_frame_no(flow_image, frame_no)
origin_img = put_frame_no(origin_img, frame_no)
frame_no += 1
vis_frame = np.concatenate((origin_img, flow_image), axis=1)
cv.imshow('flow image', vis_frame)
# cv.imshow('origin', flow_image)
k = cv.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv.imwrite('opticalfb.png', origin_img)
cv.imwrite('opticalhsv.png', flow_image)
prv_frame = next_frame
cv.destroyAllWindows()

Unsupervised Image Segmentation based on object shape

Is there any unsupervised method ( i.e. not requiring a training dataset) to separate the objects on the figure below based on shape?
I want to get something like that
where the orange lines separate the elongated objects from the "round" ones
This worked for me.
import cv2
import numpy as np
from copy import deepcopy
path = "Image.png"
image = cv2.imread(path, 0)
image_copy = deepcopy(image)
rad = 18
shape_type = cv2.MORPH_RECT
element = cv2.getStructuringElement(shape_type, (2 * rad + 1, 2 * rad + 1), (rad, rad))
image = cv2.dilate(image, element)
image_show = ~cv2.erode(image, element)
backtorgb = cv2.cvtColor(image_copy, cv2.COLOR_GRAY2RGB)
contour, hier = cv2.findContours(image_show, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for cnt in contour:
area = cv2.contourArea(cnt)
perimeter = cv2.arcLength(cnt,True)
if (area > 12000) & (area / perimeter**2 * 4 * 3.14 > 0.3):
blue = 0
green = 0
red = 255
else:
red = 0
green = 0
blue = 0
cv2.drawContours(backtorgb, [cnt], 0, (blue, green, red), -1)
imS = cv2.resize(backtorgb, (960, 540))
cv2.imshow("image2", imS)
cv2.imwrite("output.png", backtorgb)
cv2.waitKey(0)
The output:

Remove coins shadow using opencv

I am trying to count how many coins there are in the image using the latest version of OpenCV, but I am struggling with the shadows.
The Canny Edge detector method is being used but as you can see in the second image, it is not working as expected because of the shadows... Any ideas about how I could deal with this problem?
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (7, 7), 0)
median = np.median(image)
lower = int(max(0, 0.67 * median))
upper = int(min(255, (1.33) * median))
canny = cv2.Canny(blurred, lower, upper)
contours, hierachy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
coins = cv2.drawContours(image, contours, -1, (0, 255, 0), 2)
cv2.imshow("Coins", coins)
You can use the coin selection by color.
import cv2 as cv
import numpy as np
low_H = 0
low_S = 50
low_V = 0
high_H = 255
high_S = 255
high_V = 255
frame = cv.imread('PzB9I.png')
frame_HSV = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
frame_threshold = cv.inRange(frame_HSV, (low_H, low_S, low_V), (high_H, high_S, high_V))
# filling holes
im_floodfill = frame_threshold.copy()
h, w = frame_threshold.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
cv.floodFill(im_floodfill, mask, (0,0), 255);
im_floodfill_inv = cv.bitwise_not(im_floodfill)
mask = frame_threshold | im_floodfill_inv
# find contours
contours, hierachy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
coins = cv.drawContours(frame, contours, -1, (0, 255, 0), 1)
cv.imshow("Coins", coins)

Hough Lines Detection inconsistent from frame to frame

The HOUGH lines (RED and WHITE) I get vary from one frame of video to the next even though the scene is static.
There is also lots of variation in the Canny results from frame to frame. This problem is not so bad here with my test case but for a real street scene, the Canny detected edges really go nuts from frame to frame.
As can be seen, many lines also simply get missed.
I realize that the noise is different from frame to frame but the conversion to grayscale and subsequent blur make the input images very close (at least to my eye).
What is going on and is there any way to fix this?
# Python 2/3 compatibility
import sys
PY3 = sys.version_info[0] == 3
if PY3:
xrange = range
import numpy as np
import cv2
import math
from time import sleep
cap = cv2.VideoCapture(0)
if __name__ == '__main__':
SLOPE = 2.0
while(True):
sleep(0.2)
ret, src = cap.read()
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
gray_blur = cv2.medianBlur(gray, 5)
gray_blur_canny = cv2.Canny(gray_blur, 25, 150)
cv2.imshow("src", src)
cv2.imshow("gray_blur", gray_blur)
cv2.imshow("gray_blur_canny", gray_blur_canny)
cimg = src.copy() # numpy function
lines = cv2.HoughLinesP(
gray_blur_canny,
1,
math.pi/180.0,
40,
np.array([]),
50,
10)
if lines is not None:
a,b,c = lines.shape
for i in range(a):
numer = lines[i][0][3] - lines[i][0][1] + 0.001;
denom = lines[i][0][2] - lines[i][0][0];
if (denom == 0):
denom = 0.001;
slope = abs(numer/denom);
print slope
if (slope > SLOPE):
cv2.line(
cimg,
(lines[i][0][0], lines[i][0][1]),
(lines[i][0][2], lines[i][0][3]),
(0, 0, 255),
3,
cv2.LINE_AA)
if (slope < (1.0/SLOPE)):
cv2.line(
cimg,
(lines[i][0][0], lines[i][0][1]),
(lines[i][0][2], lines[i][0][3]),
(200, 200, 200),
3,
cv2.LINE_AA)
cv2.imshow("hough lines", cimg)
ch = cv2.waitKey(1)
if ch == 27:
break
cv2.destroyAllWindows()

Detect Narrow Line in very noise image

I have performed preprocessing steps in an noisy acoustic image and now I need to detect narrow black lines.
Can you think of a better way to detect these lines?
My goal is to detect the line in the red box in this image.
Failed Answer: - This is not a perfect solution but will require further work to make it robust for various images. I noticed that there is very less noise in the black lines, and thus Canny does not found a lot of edges within this region. Code and results below:-
import numpy as np
import cv2
gray = cv2.imread('2.png')
edges = cv2.Canny(gray,10,60,apertureSize = 7)
cv2.imwrite('2-1-edges-10-60.jpg',edges)
kernel = np.ones((5,5),np.uint8)
closeEdges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
cv2.imwrite('2-2-edges-10-60-dilated-1.jpg',closeEdges)
invertEdges = 255 - closeEdges
cv2.imwrite('2-3-invertedges-10-60.jpg',invertEdges)
minLineLength=100
lines = cv2.HoughLinesP(image=invertEdges,rho=1,theta=np.pi/180, threshold=200,lines=np.array([]), minLineLength=minLineLength,maxLineGap=80)
a,b,c = lines.shape
for i in range(a):
cv2.line(gray, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 1, cv2.LINE_AA)
cv2.imwrite('2-4-houghlines.jpg',gray)
Using connected component on inverse of output image and finding maximum size elements could be helpful.
Another way of approaching this is use of gradient image and directly finding area of small range of gradient magnitude. This approach would be much more flexible as it will not require using fixed threshold values - 10 and 60 as above. Threshold values can be adaptive according to image gradient/you can normalize gradient of image before using hard-coded thresholds.
Better Answer(30-40% accurate)
import numpy as np
import cv2
import os
# Store all images in this folder
path='images-1'
def autocrop(image, threshold=0):
if len(image.shape) == 3:
flatImage = np.max(image, 2)
else:
flatImage = image
rows = np.where(np.max(flatImage, 0) > threshold)[0]
if rows.size:
cols = np.where(np.max(flatImage, 1) > threshold)[0]
image = image[cols[0]: cols[-1] + 1, rows[0]: rows[-1] + 1]
else:
image = image[:1, :1]
return image
def skeleton(img):
size = np.size(img)
skel = np.zeros(img.shape,np.uint8)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
done = False
while( not done):
eroded = cv2.erode(img,element)
temp = cv2.dilate(eroded,element)
temp = cv2.subtract(img,temp)
skel = cv2.bitwise_or(skel,temp)
img = eroded.copy()
zeros = size - cv2.countNonZero(img)
if zeros==size:
done = True
return skel
def gamma_correction(img, correction):
img = img/255.0
img = cv2.pow(img, correction)
return np.uint8(img*255)
def auto_canny(image, sigma=0.33):
# compute the median of the single channel pixel intensities
v = np.median(image)
# apply automatic Canny edge detection using the computed median
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
edged = cv2.Canny(image, lower, upper)
# return the edged image
return edged
for file in os.listdir(path):
if file.endswith(".png"):
current = os.path.join(path, file)
img = cv2.imread(current, 0)
print 'processing ' + current
img = autocrop(img, 0)
cv2.imwrite(current + '-0-cropped.jpg', img)
height, width = img.shape[:2]
img = cv2.resize(img, (width, width))
cv2.imwrite(current + '-0-resized.jpg', img)
# cv2.imwrite(current +'-2-auto_canny_default.jpg', auto_canny(img))
# img = cv2.medianBlur(img,5)
# cv2.imwrite(current +'-0-medianBlur.jpg',img)
# th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
# cv2.imwrite(current +'-1-threshold_gaussian.jpg',th3)
# laplacian = cv2.Laplacian(img,cv2.CV_64F)
# cv2.imwrite(current + '-3-threshold_gaussian.jpg', laplacian)
#img = cv2.bilateralFilter(img, 3, 3, 5)
edges = cv2.Canny(img,10,20,apertureSize = 5)
cv2.imwrite(current +'-1-edges-10-60.jpg',edges)
kernel = np.ones((3,3),np.uint8)
edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
cv2.imwrite(current +'-1-edgesClosed-10-60.jpg', edges)
edges = 255-edges
cv2.imwrite(current +'-2-edgesClosedInverted-10-60.jpg', edges)
im2, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
imgColor = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
maxArea = 0
for cnt in contours:
if maxArea < cv2.contourArea(cnt):
maxArea = cv2.contourArea(cnt)
for cnt in contours:
rect = cv2.minAreaRect(cnt) #I have used min Area rect for better result
width = rect[1][0]
height = rect[1][1]
if cv2.contourArea(cnt) > int(maxArea/2.5) and ( width < height/2 or height < width/2):
cv2.drawContours(imgColor, cnt, -1, (0,255,0), 1)
cv2.imwrite(current+'-5-Contours.jpg',imgColor)
# edges = skeleton(255-edges)
# cv2.imwrite(current +'-2-skeleton.jpg', edges)
# edges = 255-edges
# minLineLength=int(width/4)
# threshold = 20
# maxLineGap = 1
# rho = 1
# lines = cv2.HoughLinesP(image=edges,rho=rho,theta=np.pi/180, threshold=threshold,lines=np.array([]), minLineLength=minLineLength,maxLineGap=maxLineGap)
# if lines is not None:
# a,b,c = lines.shape
# for i in range(a):
# cv2.line(img, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 1, cv2.LINE_AA)
# cv2.line(edges, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 1, cv2.LINE_AA)
# cv2.imwrite(current+'-5-houghlines.jpg',img)
# cv2.imwrite(current+'-6-houghlines.jpg',edges)
# print 'cool'
# else:
# cv2.imwrite(current+'-5-houghlines.jpg',img)
Also, do check following links:
Detection of Continuous, Smooth and Thin Edges in Noisy Images Using Constrained Particle Swarm Optimisation
http://www.imagemagick.org/discourse-server/viewtopic.php?t=14491
http://answers.opencv.org/question/3454/detecting-thick-edges/

Resources