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

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()

Related

Hough Line Transform in Python keeps throwing error

I'm trying to use opencv to do a simple Lane Keep Assist System but I'm getting this error from the Hough Transform function:
cv2.error: OpenCV(4.6.0)
/io/opencv/modules/highgui/src/precomp.hpp:155: error: (-215:Assertion
failed) src_depth != CV_16F && src_depth != CV_32S in function
'convertToShow'
This is the code I have:
import cv2
import numpy as np
def detect_line_segments(frame):
# tuning min_threshold, minLineLength, maxLineGap is a trial and error process by hand
rho = 1 # distance precision in pixel, i.e. 1 pixel
angle = np.pi / 180 # angular precision in radian, i.e. 1 degree
min_threshold = 2 # minimal of votes
# frame = frame.astype(np.uint8)
line_segments = cv2.HoughLinesP(frame, rho, angle, min_threshold, minLineLength=8, maxLineGap=4)
return line_segments
def detectEdges(frame):
rho = 1
angle = np.pi / 180
min_threshold = 10
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_blue = np.array([60, 40, 40])
upper_blue = np.array([150, 255, 255])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
mask = cv2.resize(mask, (960, 540))
# cv2.imshow('Test', mask)
# cv2.waitKey(0)
edges = cv2.Canny(mask, 200, 400)
#edgesUpdt = np.array(edges, dtype=np.uint8)
# cv2.imshow('Test', edgesUpdt)
# cv2.waitKey(0)
return edges
def region_of_interest(edges):
print(edges)
height, width = edges.shape
mask = np.zeros_like(edges)
# only focus bottom half of the screen
polygon = np.array([[
(0, height * 1 / 2),
(width, height * 1 / 2),
(width, height),
(0, height),
]], np.int32)
cv2.fillPoly(mask, polygon, 255)
cropped_edges = cv2.bitwise_and(edges, mask)
cv2.imshow('Test', cropped_edges)
cv2.waitKey(0)
return cropped_edges
def detect_line_segments(cropped_edges):
# cropped_edges = cropped_edges.astype(np.float32)
cv2.imshow('Test', cropped_edges)
cv2.waitKey(0)
# tuning min_threshold, minLineLength, maxLineGap is a trial and error process by hand
rho = 2 # distance precision in pixel, i.e. 1 pixel
angle = np.pi / 60 # angular precision in radian, i.e. 1 degree
min_threshold = 50 # minimal of votes
line_segments = cv2.HoughLinesP(cropped_edges, rho, angle, min_threshold,
np.array([], dtype=np.uint8), minLineLength=40, maxLineGap=80)
cv2.imshow('Test', line_segments)
cv2.waitKey(0)
return line_segments
def main():
frame = cv2.imread(r'/home/a1ph4/Desktop/LKAS system/Media/image.jpg')
edges = detectEdges(frame)
# test1 = region_of_interest(edges)
croppedEdges = detect_line_segments(edges)
if __name__ == '__main__':
main()
And this is the image I'm using
Image
Please help.

How to have normal speed of output video in my Dense Optical Flow model?

My code below is from https://docs.opencv.org/3.4/d4/dee/tutorial_optical_flow.html, idk why the output video is so slow, how to change back to normal speed guys?
cap = cv.VideoCapture('NY.avi')
ret, frame1 = cap.read()
prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
while(1):
ret, frame2 = cap.read()
next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY)
flow = cv.calcOpticalFlowFarneback(prvs,next, 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)
bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR)
cv.imshow('frame2',bgr)
k = cv.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv.imwrite('opticalfb.png',frame2)
cv.imwrite('opticalhsv.png',bgr)
prvs = next

OpenCv Get edge distance to circle center

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

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