I am using cv2.VideoWriter() as an intermediate step in a larger image processing workflow. Basically I have a stack of images that need to be turned into a timelapse, and then the frames in that are processed and then used downstream to mask original imagery. My masking isn't working because array sizes to not correspond with one another, and I've diagnosed the problem to arise from cv2.VideoWriter(). My time lapse assembly process came from here.
There are a ton of posts about cv2.VideoWriter() not working because the frame size is wrong etc. but my problem is not that the video won't write - it's that dimensions of my imagery are being changed. In fact, I'm not even sure if the top row or bottom row is what's being cut off, or if there is some underlying resampling step or something.
import cv2
import numpy as np
import glob
imgs = glob.glob('*.jpg')
img_array = []
for filename in imgs:
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
img_array.append(img)
size # calling `size` returns (250,187)
out = cv2.VideoWriter('project.avi',cv2.VideoWriter_fourcc(*'DIVX'), 15, size)
for i in range(len(img_array)):
out.write(img_array[i])
out.release()
cap = cv2.VideoCapture('project.avi')
mycap = cap.read()
mycap[1].shape # this returns (186,250,3)
I would have expected mycap[1].shape to have the same attributes as size but while size indicates I have a 250 pixel wide and 187 pixel tall array, mycap[1].shape shows that the video has dimensions 250x186.
After some testing I confirmed that cv2.VideoWriter() is not simply clipping an image with odd dimension values, but is instead altering values in the arrays while changing dimensions:
import numpy as np
import pylab as plt
import cv2 as cv
# Create RGB layers
r = np.array([[255, 0, 255, 0, 255, 0, 255, 0, 255], [255, 0, 255, 0, 255, 0, 255, 0, 255], [255, 0, 255, 0, 255, 0, 255, 0, 255]],dtype=np.uint8)
g = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]],dtype=np.uint8)
b = np.array([[10, 0, 10, 0, 10, 0, 255, 0, 255], [10, 0, 10, 0, 10, 0, 255, 0, 255], [10, 0, 10, 0, 10, 0, 255, 0, 255]],dtype=np.uint8)
# Create a few image layers
rgb1 = np.dstack((r,g,b))
rgb2 = np.dstack((r,g,b))
rgb3 = np.dstack((r,g,b))
rgb4 = np.dstack((r,g,b))
plt.imshow(rgb1)
imgs = [rgb1,rgb2,rgb3,rgb4]
# Create timelapse
img_array = []
for img in imgs:
height, width, layers = img.shape
size = (width,height)
img_array.append(img)
out = cv.VideoWriter('SO_question.avi',cv.VideoWriter_fourcc(*'DIVX'), 15, size)
for i in range(len(img_array)):
out.write(img_array[i])
out.release()
# Read video in
cap = cv.VideoCapture('SO_question.avi')
cap.read()[1].shape
plt.imshow(cap.read()[1])
plt.imshow(rgb1) produces the following image:
But plt.imshow(cap.read()[1]) produces the following image:
Furthermore, using print(cap.read()[1]) shows that array values are not maintained across the process. Thus, I conclude that a resampling process is occurring (rather than a simple crop step) when width and height are an odd number of pixels.
Related
I made a color mask with cv2 and all I need to do is get the average position of all the white pixels on the mask which are labeled 255. My array looks something like this:
[
[0, 0, 0, 0, 255, 255, ...],
[0, 0, 0, 0, 255, 255, ...],
[0, 0, 0, 0, 255, 255, ...],
[0, 0, 0, 0, 255, 255, ...],
...
]
The size of the screen is 400px high and 600px wide so I can't use it for loops without it looking like an android camera from 2014. I've seen a lot of tutorials on how to average the pixel value but not the position. Is anyone able to help me out?
I was wondering if there is a way to make an array/column like [255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255....] that repeats until a certain length (length of a imported image) for every row/array. The goal of this will be to make an image that will show 255 as white "pixels" and 0 as the black "pixels". Is this possible?
proposed mask concept
final result
import numpy as np
from skimage import data
from skimage import io
path = r'C:\C:\Python36\bmp_files\slide_3.png'
sz = 400
image = data.astronaut()
patch1 = image[250:250+sz,250:250+sz,:]
patch1.shape
#(48, 48, 3)
mask = np.tile(np.array([[[1],[0]],[[0],[0]]],dtype=np.uint8),(sz/2,sz/2,3))
mask.shape
#(48, 48, 3)
print (mask)
patch2 = patch1 * mask
patch12 = np.hstack((patch1,patch2))`
i am new in python , my probleme it's about edit some changes in an image grayscale , i wanna make a binarization for this image , the values of pixels bigger then 100 take the value 1 (white), and the values low than 100 takes the value 0 (black)
so any suggestion plz (sorry for my bad english)
my code :
`import numpy as np
import cv2
image = cv2.imread('Image3.png', 0)
dimension = image.shape
height = dimension[0]
width = dimension[1]
#finalimage = np.zeros((height, width))
for i in range(height) :
for j in range(width):
if (image[i, j] > 100):
image[i][j] = [1]
else:
image[i][j] = [0]
cv2.imshow('binarizedImage',image)
cv2.waitKey(0)
cv2.destroyAllWindows()
You can try use OpenCV function cv2.threshold for binarize.
import cv2
img = cv2.imread('Image3.png', cv2.IMREAD_GRAYSCALE)
thresh = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)[1]
cv2.imshow('binarizedImage',thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
I think you just want to use np.where():
import numpy as np
image = np.array([[200, 50, 200],[50, 50 ,50],[10, 255, 10]]) #this will be your image instead
In [11]: image
Out[11]:
array([[200, 50, 200],
[ 50, 50, 50],
[ 10, 255, 10]])
In [12]: np.where(image > 100, 1, 0)
Out[12]:
array([[1, 0, 1],
[0, 0, 0],
[0, 1, 0]])
Super simple question, I have a single channel image consisting of 0's and 255's and I would like to convert it into a 4 channel image of [0,0,0,0] and [255,255,255,255] in the most efficient manner possible. cv2.COLOR_GRAY2RGBA causes the alpha to all be at 255 and np.where() feels like black magic to me so any help would be appreciated.
One-liner solution using cv2.merge function.
Let your input image be "img" which is of 1 channel.
To convert it to 4 channel, do this:
img = cv2.merge((img.copy(), img.copy(), img.copy(), img.copy()))
Now the "img" will contain 4 channels and all the channels will be the same wrt values.
Just create a numpy array with more layers and then change the values of this array to the values of your image.
img = cv2.imread('img.jpg')
h, w, d = img.shape #(217, 232, 3)
nr_of_new_layers = 1
alpha_img = np.zeros((h, w, d+nr_of_new_layers))
alpha_img[:,:,:3] = img #alpha_img shape = (217, 232, 4)
Or if there isn't any 3rd dimension then you can do
d = 0
img = cv2.imread('img.jpg', d)
h, w = img.shape #(217, 232)
nr_of_new_layers = 4
alpha_img = np.zeros((h, w, d+nr_of_new_layers))
alpha_img[:,:,d] = img #alpha_img shape = (217, 232, 4)
Just stack 4 copies of your single channel image with np.dstack():
RGBA = np.dstack((im,im,im,im)) # or more tersely RGBA = np.dstack(([im]*4))
Example:
import numpy as np
# Make image
im = np.array([0,255,255,0,0], dtype=np.uint8)
Look at it:
array([ 0, 255, 255, 0, 0], dtype=uint8)
Stack it depth-wise with np.dstack():
RGBA = np.dstack((im,im,im,im))
Look at it:
array([[[ 0, 0, 0, 0],
[255, 255, 255, 255],
[255, 255, 255, 255],
[ 0, 0, 0, 0],
[ 0, 0, 0, 0]]], dtype=uint8)
I have been trying to reduce the noise in the attached image. Basically, I want to remove the background dust from the image. Currently, I have tried looking for small points throughout the image(anything that fits within a 10 by 10 grid with low Green pixel intensity) and then blacked out the 10 by 10 region. However, I was hoping to remove more noise from the image. Is there a possibly way to run some filters in OpenCv to do so.
A simple approach can be: Convert the image to grayscale, threshold it, and the apply morphological opening in it to get estimate results.
img = cv2.imread("commitdust.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, th = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY)
k = np.array([[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0]], dtype=np.uint8)
th = cv2.morphologyEx(th, cv2.MORPH_OPEN, k)
cv2.imshow("th", th)
cv2.waitKey(0)
cv2.destroyAllWindows()