Reputation: 69
I'm working on lane detection on images. I a have a function that takes a path to an image and returns an image with lanes detected. I need to write another function thae takes a path to a directory with multiple images and output path as input, uses the first function to process an image and then save it in an output directory.
This is the code from the beginning, where I define helper functions if you want to reproduce it:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
%matplotlib inline
def to_gray(image):
gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
return gray
def blur_gray(gray):
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)
return blur_gray
def Canny(blur_gray):
low_threshold = 100
high_threshold = 200
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)
return edges
def masked_edges(image, edges):
mask = np.zeros_like(edges)
ignore_mask_color = 255
imshape = image.shape
vertices = np.array([[(130,imshape[0]),(420, 325), (540,325), (850,imshape[0])]], dtype=np.int32)
cv2.fillPoly(mask, vertices, ignore_mask_color)
masked_edges = cv2.bitwise_and(edges, mask)
return masked_edges
def lines (masked_edges, image):
# Define the Hough transform parameters
# Make a blank the same size as our image to draw on
rho = 1 # distance resolution in pixels of the Hough grid
theta = np.pi/180 # angular resolution in radians of the Hough grid
threshold = 1 # minimum number of votes (intersections in Hough grid cell)
min_line_length = 3 #minimum number of pixels making up a line
max_line_gap = 4 # maximum gap in pixels between connectable line segments
line_image = np.copy(image)*0 # creating a blank to draw lines on
# Run Hough on edge detected image
# Output "lines" is an array containing endpoints of detected line segments
lines = cv2.HoughLinesP(masked_edges, rho, theta, threshold, np.array([]),
min_line_length, max_line_gap)
return lines
def draw_lines(lines, image, edges):
line_image = np.copy(image)*0 # creating a blank to draw lines o
# Iterate over the output "lines" and draw lines on a blank image
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),10)
# Create a "color" binary image to combine with line image
color_edges = np.dstack((edges, edges, edges))
# Draw the lines on the edge image
lines_edges = cv2.addWeighted(color_edges, 0.8, line_image, 1, 0)
pic_lanes = plt.imshow(lines_edges)
return pic_lanes
So this is the function that incorporates multiple helper functions from above and returns a single image:
def image_pipeline(image_path):
image = mpimg.imread(image_path)
gray = to_gray(image)
to_blur_gray = blur_gray(gray)
edges = Canny(to_blur_gray)
masked = masked_edges(image, edges)
line = lines(masked, image)
pic_lanes = draw_lines(line, image, edges)
return pic_lanes
Then I want to use the above function within a loop function that would do the same for all the images from an input directory and save them in an output directory.
def video_loop(outPath, path):
image_no = 1
for image_path in os.listdir(path):
# create the full input path and read the file
input_path = os.path.join(path, image_path)
pic_lanes = image_pipeline(input_path)
fullpath = os.path.join(outPath, image_path)
name = fullpath + '.jpg'
cv2.imwrite(name, pic_lanes)
os.chdir(fullpath)
image_no += 1
if __name__ == '__video_loop__':
video_loop()
out= '/content/CarND-LaneLines-P1/Solid White Frames Canny'
path1 = '/content/CarND-LaneLines-P1/Frames Solid White Right'
video_loop(out, path1)
Unfortunately I get an error together with one returned image:
TypeError Traceback (most recent call last)
<ipython-input-109-10dea7ed1446> in <module>()
1 out= '/content/CarND-LaneLines-P1/Solid White Frames Canny'
2 path1 = '/content/CarND-LaneLines-P1/Frames Solid White Right'
----> 3 video_loop(out, path1)
<ipython-input-108-a52f4438bc0d> in video_loop(outPath, path)
8 fullpath = os.path.join(outPath, image_path)
9 name = fullpath + '.jpg'
---> 10 cv2.imwrite(name, pic_lanes)
11 os.chdir(fullpath)
12 image_no += 1
TypeError: Expected Ptr<cv::UMat> for argument '%s'
I have searched for the meaning of this error and someone suggested that the cv2.imwrite()
doesn't get a valid argument (the picture doesn't exist) but I'm not sure how to fix this.
EDIT: I also tried something simpler like this:
count=0
for filename in os.listdir('/content/CarND-LaneLines-P1/Frames Solid White Right'):
detected_lanes = image_pipeline(filename)
detected_lanes = cv2.imread(detected_lanes)
cv2.imwrite(filename, detected_lanes)
os.chdir('/content/CarND-LaneLines-P1/Frames Solid White Right/Canny')
count =+1
But i'm gettin a different error here:
SystemError Traceback (most recent call last)
<ipython-input-15-1d3fff5ab2bb> in <module>()
2 for filename in os.listdir('/content/CarND-LaneLines-P1/Frames Solid White Right'):
3 detected_lanes = image_pipeline(filename)
----> 4 detected_lanes = cv2.imread(detected_lanes)
5 cv2.imwrite(filename, detected_lanes)
6 os.chdir('/content/CarND-LaneLines-P1/Frames Solid White Right/Canny')
SystemError: <built-in function imread> returned NULL without setting an error
I don't know how to approach this. If you want to run this code, just use the code provided and then use image_pipeline
and pass it any image.
Any chance you could help me out here?
Upvotes: 0
Views: 433
Reputation: 69
I have managed to solve my problem by passing a save function within my pipeline and only then ran a loop.
First I changed draw_lines
function to also save the image:
def draw_lines(lines, image, edges, image_path, path_to_save_files):
copy = np.copy(image)
line_image = np.copy(image)*0 # creating a blank to draw lines o
# Iterate over the output "lines" and draw lines on a blank image
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),10)
# Create a "color" binary image to combine with line image
color_edges = np.dstack((edges, edges, edges))
# Draw the lines on the edge image
my_dpi=96
lines_edges = cv2.addWeighted(color_edges, 0.8, line_image, 1, 0)
final = cv2.addWeighted(lines_edges, 0.5, image, 0.7, 50)
plt.figure(figsize=(960/my_dpi, 540/my_dpi), dpi=my_dpi)
final_image = plt.imshow(final)
plt.axis('off')
save_fname = os.path.join(outpath, os.path.basename(image_path))
plt.savefig(save_fname, bbox_inches='tight', pad_inches=0, transparent=True)
I used plt.savefig()
by passing it save_fname
that changes accordingly with every image (it takes the path to the directory where I want to store my images together with just the name of the file derived from its original path). Additionally, I didn't want my picture to be in a form of a matrix so I used plt.axis('off')
.
I then used a simple for loop:
count= 0
for file in os.listdir(path_with_images):
image_pipeline(file, path_to_save_files)
count=+1
This works great for me.
Upvotes: 1