detecting coloured lines and grabing image between two coloured lines python opencv - python

I have written a python code using opencv and numpy to detect red colour lines in a video and it is working fine as it is able to detect the edges of the red lines. but i want to grab the part of the video in between each two lines as images.how to do that ?? Now I have updated an image. i want to extract the image in between two red lines from the video.
import cv2
import numpy as np
import matplotlib.pyplot as plt
video = cv2.VideoCapture("/home/ksourav/AGS/SampleVideos/Trail1.mp4")
while True:
ret, frame = video.read()
if not ret:
video = cv2.VideoCapture("/home/ksourav/AGS/SampleVideos/Trail1.mp4")
continue
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
low_red = np.array ([5, 50, 50])
up_red = np.array([10, 255, 255])
mask = cv2.inRange(hsv, low_red, up_red)
edges= cv2.Canny(mask, 100, 200, apertureSize=7, L2gradient=True)
lines = cv2.HoughLinesP(edges, 9, np.pi/180, 250, maxLineGap=70)
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imshow("frame", frame)
key = cv2.waitKey(25)
if key == 27:
break
video.release()
cv2.destroyAllWindows()

Related

detect moving object with opencv and python

i found very interesting article about detection of moving objects, here is correspondng link :Detection of moving object
and also corresponding article : Article about object detection
i followed code and try to implement my self, here is corresponding code :
import cv2
import numpy as np
import matplotlib.pyplot as plt
from Background_Image_Creation import get_background
cap =cv2.VideoCapture("video_1.mp4")
#print(cap.get(cv2.CAP_PROP_FRAME_COUNT))
#print(cap.get(cv2.CAP_PROP_FPS))
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
save_name = "Result.mp4"
# define codec and create VideoWriter object
out = cv2.VideoWriter(save_name,cv2.VideoWriter_fourcc(*'mp4v'), 10, (frame_width, frame_height))
background_frame =get_background("video_1.mp4")
background = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)
print(background.shape)
frame_count =0
consecutive_frame=8
#frame_diff_list =[]
while cap.isOpened():
ret,frame =cap.read()
print(ret)
print(frame.shape)
if ret==True:
frame_count+=1
orig_frame =frame.copy()
gray =cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
if frame_count % consecutive_frame == 0 or frame_count == 1:
frame_diff_list =[]
frame_diff = cv2.absdiff(gray, background)
ret, thresh = cv2.threshold(frame_diff, 50, 255, cv2.THRESH_BINARY)
dilate_frame = cv2.dilate(thresh, None, iterations=2)
frame_diff_list.append(dilate_frame)
print(frame_diff_list)
if len(frame_diff_list) == consecutive_frame:
# add all the frames in the `frame_diff_list`
sum_frames = sum(frame_diff_list)
print(sum_frames)
# find the contours around the white segmented areas
contours, hierarchy = cv2.findContours(sum_frames, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# draw the contours, not strictly necessary
for i, cnt in enumerate(contours):
cv2.drawContours(frame, contours, i, (0, 0, 255), 3)
for contour in contours:
# continue through the loop if contour area is less than 500...
# ... helps in removing noise detection
if cv2.contourArea(contour) < 500:
continue
# get the xmin, ymin, width, and height coordinates from the contours
(x, y, w, h) = cv2.boundingRect(contour)
# draw the bounding boxes
cv2.rectangle(orig_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('Detected Objects', orig_frame)
out.write(orig_frame)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
code for background frame creation is also presented :
import numpy as np
import cv2
import matplotlib.pyplot as plt
def get_background(path):
cap =cv2.VideoCapture(path)
frame_indices =cap.get(cv2.CAP_PROP_FRAME_COUNT)*np.random.uniform(size=50)
frames =[]
for idx in frame_indices:
cap.set(cv2.CAP_PROP_POS_FRAMES,idx)
ret,frame =cap.read()
frames.append(frame)
median_frame = np.median(frames, axis=0).astype(np.uint8)
return median_frame
#median_frame =get_background("video_1.mp4")
#cv2.imshow("Median_Background",median_frame)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
#plt.show()
code runs fine, but output video does not contain anything, it just 1 KGB size, one thing what i am thinking is that this fragment
frame_diff_list.append(dilate_frame)
is colored with yellow color, here is screenshot :
and also when i try to print print(frame_diff_list)
it just printed one output :
i was more surprised when i have tested
print(ret)
print(frame.shape)
from the begining of the loop and it just printed one output :
True
(360, 640, 3)
it seems that loop does not cover all frames right? could you help me please to figure out what is wrong with my code?

Crop image into different parts based on the detected lines using OpenCV

I have detected dotted lines using HoughLinesP on some image samples and draw red lines on them. For example, look at the image below:
The code for detecting the lines is below:
import cv2
import numpy as np
import math
img = cv2.imread("tabulapy/image2.png")
img = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
kernel1 = np.ones((1, 5), np.uint8)
kernel2 = np.ones((9, 9), np.uint8)
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgBW = cv2.threshold(imgGray, 230, 255, cv2.THRESH_BINARY_INV)[1]
img1 = cv2.erode(imgBW, kernel1, iterations=1)
img2 = cv2.dilate(img1, kernel2, iterations=3)
img3 = cv2.bitwise_and(imgBW, img2)
img3 = cv2.bitwise_not(img3)
img4 = cv2.bitwise_and(imgBW, imgBW, mask=img3)
imgLines = cv2.HoughLinesP(img4, 1, np.pi / 180, 10, minLineLength=500, maxLineGap=2)
for i in range(len(imgLines)):
for x1, y1, x2, y2 in imgLines[i]:
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
I want to crop this image into different parts based on the detected lines(red lines). What I mean, the first image would be from the top to the first detected red line; the second image would be the first detected red line to the second detected red line, and so on...
Does anyone have any idea how it can be done?

Probabilistic Hough lines returning only angled lines

I'm attempting to parse floorplans to turn them into an array of line coordinates using HoughLinesP in opencv-python and the function is only returning lines that are angled and have no relation to the actual lines in my image.
Here is my code:
import cv2
# Read image and convert to grayscale
img = cv2.imread('C:/Data/images/floorplan/extremely basic.png', -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Get lines with probabilistic hough lines
found_lines = cv2.HoughLinesP(gray, 1, 3.14 / 160, 100,
minLineLength=1, maxLineGap=10)
# Loop through found lines and draw each line on original image
for line in found_lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1)
# Show image, wait until keypress, close windows.
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
And here is what's going to be returned with threshold 150 and 100 respectively:
I've tried tinkering with all options and attempted non-probabilistic Hough lines to no avail.
The problem was with image inversion and parameters. You have to do further adjustments as this does not give all lines.
The code is test on google colab. Remove from google.colab.patches import cv2_imshow and replace cv_imshow with cv2.imshow for local usage.
Partial Image Ouput
Code
import cv2
import numpy as np
from google.colab.patches import cv2_imshow
# Read image and convert to grayscale
img = cv2.imread('1.jpg', 0)
#gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
s1, s2 = img.shape
new_img = np.zeros([s1,s2],dtype=np.uint8)
new_img.fill(255)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
cv2_imshow(thresh1)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(thresh1,kernel,iterations = 1)
cv2_imshow(erosion)
# Get lines with probabilistic hough lines
found_lines = cv2.HoughLinesP(erosion, np.pi/180, np.pi/180, 10, minLineLength=4, maxLineGap=4)
# Loop through found lines and draw each line on original image
for line in found_lines:
x1, y1, x2, y2 = line[0]
cv2.line(new_img, (x1, y1), (x2, y2), (0, 0, 255), 1)
cv2_imshow(new_img)
#cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1)
# Show image, wait until keypress, close windows.
print("ORIGINAL IMAGE:")
cv2_imshow(img)
#cv2.imshow('image', img)
#cv2.waitKey(0)
#cv2.destroyAllWindows()

How to detect the yellow object that obscured by shadows?

I try to detect the yellow line in the following picture but shadows obscured the yellow roads. Do we have any method to deal with that?
We can detect the yellow in this question:About Line detection by using OpenCV and How to delete the other object from figure by using opencv?.
The coding is as follows:
import cv2
import numpy as np
image = cv2.imread('Road.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
low_yellow = np.array([18, 94, 140])
up_yellow = np.array([48, 255, 255])
mask = cv2.inRange(hsv, low_yellow, up_yellow)
edges = cv2.Canny(mask, 75, 150)
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 50, maxLineGap=250)
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 5)
# cv2.imshow('image', img)
cv2.imwrite("result.jpg", edges)
Here is the code to convert to lab and auto-threshold
You'll have to detect the lines using a proper method.
An advanced solution would be training a dataset to do segmentation (neural network Ex : Unet )
import cv2
import numpy as np
img = cv2.imread('YourImagePath.jpg')
cv2.imshow("Original", img)
k = cv2.waitKey(0)
# Convert To lab
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
# display b channel
cv2.imshow("Lab", lab[:, :, 2])
k = cv2.waitKey(0)
# auto threshold using Otsu
ret , mask = cv2.threshold(lab[:, :, 2] , 0 , 255 , cv2.THRESH_BINARY+
cv2.THRESH_OTSU)
#display Binary
cv2.imshow("Binary", mask)
k = cv2.waitKey(0)
cv2.destroyAllWindows()
Output:

Display the bottom image of the line and cut the upper image using Opencv

I am trying to crop the live video diagonally. With the help of cv.line, I have mentioned the dimensions and my goal is to display the video of the lower side of the line I have drawn and the upper video should be cropped,
As a beginner, I was just able to draw a line using the following code:
import cv2
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
if vc.isOpened(): # try to get the first frame
rval, frame = vc.read()
else:
rval = False
while rval:
cv2.imshow("preview", frame)
rval, frame = vc.read()
key = cv2.waitKey(20)
if key == 27: # exit on ESC
break
else:
cv2.line(img=frame, pt1=(700,5), pt2=(5, 450), color=(255, 0, 0), thickness=1, lineType=8, shift=0)
vc.release()
cv2.destroyWindow("preview")
Output:
Suggestion on this will be very helpful
Here's the code that'll mask out the points above the line. I've added comments here so you can follow what's going on. There are faster ways to do this, but I wanted something that would be easily readable.
import cv2
import matplotlib.pyplot as plt
import numpy as np
path = r"path\to\img"
img = cv2.imread(path)
#plt.imshow(img)
#plt.show()
pt1 = (86, 0) #ensure this point exists within the image
pt2 = (0, 101) #ensure this point exists within the image
cv2.line(img, pt1, pt2, (255, 255, 255))
#plt.imshow(img)
#plt.show()
#slope of line
m = float(pt2[1] - pt1[1])/float(pt2[0] - pt1[0])
c = pt1[1] - m*pt1[0]
#create mask image
mask1 = np.zeros(img.shape, np.uint8)
#for every point in the image
for x in np.arange(0, 87):
for y in np.arange(0, 102):
#test if point exists above the line,
if y > m*x + c:
mask1[y][x] = (255, 255, 255)
#plt.imshow(mask1)
#plt.show()
fin_img = cv2.merge((img[:, :, 0], img[:, :, 1], img[:, :, 2], mask1[:,:, 0]))
#plt.imshow(fin_img)
#plt.show()
cv2.imwrite('output.png', fin_img)
To crop images, I use a mask and cv2.bitwise_and().
Source Image:
The mask:
# Create a mask image with a triangle on it
y,x,_ = img.shape
mask = np.zeros((y,x), np.uint8)
triangle_cnt = np.array( [(x,y), (x,0), (0,y)] )
cv2.drawContours(mask, [triangle_cnt], 0, 255, -1)
The output:
img = cv2.bitwise_and(img, img, mask=mask)

Categories

Resources