I'm trying to run a code that divides a video into frames while filtering it to greyscale (using threads) and I've got this error trying to run my code:
File "C:\Users\USER\PycharmProjects\ASCIIPICproject\venv\lib\site-packages\matplotlib\artist.py", line 1160, in _update_props
raise AttributeError(
AttributeError: Line2D.set() got an unexpected keyword argument 'cmap'
this is my code (of the function for the filtering thread):
def saveFramesFiltered():
currentFrame = 0
framemax = 215
while currentFrame < framemax:
while not os.path.exists("./framesBefore/frame" + str(currentFrame) + '.jpg'):
time.sleep(0.01)
lock.acquire()
image = pltim.imread("./framesBefore/frame" + str(currentFrame) + '.jpg')
lock.release()
r, g, b = image[:, :, 0], image[:, :, 1], image[:, :, 2]
grayImage = 0.299 * r + 0.587 * g + 0.114 * b
plt.plot(grayImage, cmap="gray")
plt.axis("off")
lock.acquire()
plt.savefig("./framesAfter/grayImage" + str(currentFrame) + ".jpg", bbox_inches='tight', pad_inches=0)
lock.release()
time.sleep(0.01)
Your error comes from plt.plot(grayImage, cmap="gray") , You can find this yourself usually by checking the line of the error.
Plot plots a curve not an image so it cannot be associated to a colormap. Try plt.imshow()
Then i would avoid the use of a second while to check if you created the file, (you check if plt.savefig worked...) Maybe savefig returns an argument that you can check.
If you don't need to open the image you can win some time by doing :
# a colormap and a normalization instance
cmap = plt.cm.jet
norm = plt.Normalize(vmin=data.min(), vmax=data.max())
# map the normalized data to colors
# image is now RGBA (512x512x4)
image = cmap(norm(data))
# save the image
plt.imsave('test.png', image)
See Saving an imshow-like image while preserving resolution
If really you want to keep it put it at the end of the loop instead of the beginning, it's clearer, how does the loop even pass the first iteration ?
I am also not sure your lock.acquire method is needed while you save theimage ?
Related
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?
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.
I'm trying to test my model for some pathology images. And I need to crop them into small patches.
Here is my cropping code.
def crop_to_four_with_cropSize(image, crop_sz=None):
if crop_sz == None:
crop_sz = image.shape[0] // 2
img_sz = image.shape[0]
y = 0
x = 0
h = crop_sz
w = crop_sz
image_crop_1 = image[y:y + h, x:x + w, :]
image_crop_2 = image[-h:, x:x + w, :]
image_crop_3 = image[y:y + h, -w:, :]
image_crop_4 = image[-h:, -w:, :]
return (image_crop_1, image_crop_2, image_crop_3, image_crop_4)
And the following is the method I used for save.
def save_to_file(image, name, path='./'):
if not os.path.exists(path):
os.makedirs(path)
full_name = os.path.join(path, name)
scipy.misc.toimage(image).save(full_name)
left is orignal image,right is cropped image.
my model is color sensitive, but I have no idea why one number matrix has different degrees of brightness.
I'll appreciate your directions.
The culprit here is the scipy.misc.toimage function. According to the warning in the documentation of toimage, this function uses bytescale for scaling the array values to use the full range of a byte i.e. from 0 to 255. That is why the colors in the cropped image have better contrast.
If the image variable is an array-like object (numpy array etc.), then instead of using scipy.misc.toimage followed by save, you may use some other method to save the image to disk such as scipy.misc.imsave of SciPy or imwrite function of OpenCV.
I tried the below code, it doesn't show any error and runs properly, but changing the value of the alpha channel, doesn't show any change in image
img3 = cv2.cvtColor(img2, cv2.COLOR_BGR2BGRA)
img3[:,:,3] = 100
cv2.imshow('img1',img2)
cv2.imshow('img',img3)
cv2.waitKey(0)
works ok, but the output of both images are same and there is no seen-able change after applying alpha channel
i have already tried the below code
Your code is actually correct.
The simple answer is that OpenCV's imshow() ignores transparency, so if you want to see its effect, save your image as a PNG/TIFF (both of which support transparency) and view it with a different viewer - such as GIMP, Photoshop or feh.
As an alternative, I made a wrapper/decorator for OpenCV's imshow() that displays images with transparency overlaid on a chessboard like Photoshop does. So, starting with this RGBA Paddington image and this grey+alpha Paddington image:
#!/usr/bin/env python3
import cv2
import numpy as np
def imshow(title,im):
"""Decorator for OpenCV "imshow()" to handle images with transparency"""
# Check we got np.uint8, 2-channel (grey + alpha) or 4-channel RGBA image
if (im.dtype == np.uint8) and (len(im.shape)==3) and (im.shape[2] in set([2,4])):
# Pick up the alpha channel and delete from original
alpha = im[...,-1]/255.0
im = np.delete(im, -1, -1)
# Promote greyscale image to RGB to make coding simpler
if len(im.shape) == 2:
im = np.stack((im,im,im))
h, w, _ = im.shape
# Make a checkerboard background image same size, dark squares are grey(102), light squares are grey(152)
f = lambda i, j: 102 + 50*((i+j)%2)
bg = np.fromfunction(np.vectorize(f), (16,16)).astype(np.uint8)
# Resize to square same length as longer side (so squares stay square), then trim
if h>w:
longer = h
else:
longer = w
bg = cv2.resize(bg, (longer,longer), interpolation=cv2.INTER_NEAREST)
# Trim to correct size
bg = bg[:h,:w]
# Blend, using result = alpha*overlay + (1-alpha)*background
im = (alpha[...,None] * im + (1.0-alpha[...,None])*bg[...,None]).astype(np.uint8)
cv2.imshow(title,im)
if __name__ == "__main__":
# Open RGBA image
im = cv2.imread('paddington.png',cv2.IMREAD_UNCHANGED)
imshow("Paddington (RGBA)",im)
key = cv2.waitKey(0)
cv2.destroyAllWindows()
# Open Grey + alpha image
im = cv2.imread('paddington-ga.png',cv2.IMREAD_UNCHANGED)
imshow("Paddington (grey + alpha)",im)
key = cv2.waitKey(0)
cv2.destroyAllWindows()
And you will get this:
and this:
Keywords: Image, image processing, Python, alpha channel, transparency, overlay, checkerboard, chessboard, blend, blending. OpenCV, imshow, cv2.imshow.
Currently I have a bunch of functions that loop through images, makes some changes and then plots each image.
def second (images):
for image in images:
image = imread(image)
image = image - 100
plt.subplot(121)
plt.imshow(image)
plt.show()
Now I wanted to decorate these functions so that for there is another subplot for each image. A subplot with a normal image and a subplot with the transformed image.
However, I need to be able to access the image from the images iteration with the second function, and for each iteration use this image within the wrapper.
Is there a clean way to do this?
I found a sort of hackish way to do this:
def plt_decorate(func):
def func_wrapper(*args, **kwargs):
images = args[0]
for image in images:
im = imread(image)
mng = plt.get_current_fig_manager() #this two lines
mng.window.state('zoomed') # are just to zoom plot
plt.subplot(122),plt.imshow(im)
if args[1:]:
print( func([image], args[1:], **kwargs)) #can't return as loop ends
else:
print( func([image], **kwargs))
return func_wrapper
#plt_decorate
def second (images):
for image in images:
image = imread(image)
image = image - 100
plt.subplot(121)
plt.imshow(image)
plt.show()
A decorator aims to tranform the input before it is passed to your function. So the way you should proceed is to loop through images, mutate it or cause some side effects and then pass images to the function.
In your case it would look something like this.
def plt_decorate(func):
def func_wrapper(images):
for image in images:
im = imread(image)
mng = plt.get_current_fig_manager()
mng.window.state('zoomed')
plt.subplot(122)
plt.imshow(im)
return func(images)
return func_wrapper
#plt_decorate
def second (images):
for image in images:
image = imread(image)
image = image - 100
plt.subplot(121)
plt.imshow(image)
plt.show()
I'm tryng to get some statics from some images, and when I tryed to perform histogram equalization I get confused.
Because I tryed this:
img = io.imread(file);
img = exposure.equalize_hist(img);
And I get the warning warn("This might be a color image. The histogram will be "
Then I tryed to perform the equalization in each channel like this:
img = io.imread(file);
#img = exposure.equalize_hist(img);
height, width = len(img), len(img[0]);
r1 = [];
g1 = [];
b1 = [];
for i in range(height):
for j in range(width):
pixel = img[i, j];
r1.append(pixel[0]);
g1.append(pixel[1]);
b1.append(pixel[2]);
r = exposure.equalize_hist(r1);
g = exposure.equalize_hist(g1);
b = exposure.equalize_hist(b1);
And I get the error
AttributeError: 'list' object has no attribute 'shape'
So how should I do histogram equalization in an image with color, and if I wanna do it in an image in HSV, or CIELAB, is it the same way?!
histogram equalization
To equalize each channel separately:
from skimage import io, exposure
img = io.imread(img_path)
for channel in range(img.shape[2]): # equalizing each channel
img[:, :, channel] = exposure.equalize_hist(img[:, :, channel])
That's because img[:, :, channel] already gives you the 2d image array supported by equalize_hist, so that you don't need to create three lists (which may be considerably inefficient, by the way). The code supposes that you do have a image (3d array) with channels on the last dimension (which is the case if you load it with skimage.io.imread).
Also, it should work the same with RGB, HSV of Lab (skimage conversions will keep channels on the last dimension). For example img = color.rgb2hsv(img) or img = color.rgb2lab(img).
If you load a grey-scale image (already a 2d array), then your commented line should work (you could handle both cases with a simple if condition).
Just something else: you can drop the semicolons.