So my problem is generating an animation from the list img_array. The code above that is basically used to get an image from the folder, annotate it and then save it into the array. Was wondering if anyone would have any suggestions on how to convert the images in the image array into an animation. Any help is appreciated! TIA.
I tried FFmepg and what not but none of them seem to work. I also tried videowriter in OpenCV but when I tried to open the file I get that this file type is not supported or corrupt.
import cv2
import numpy as np
import glob
import matplotlib.pyplot as plt
from skimage import io
import trackpy as tp
import pims
import pylab as pl
##########
pixel_min=23
min_mass=5000
Selector1=[1,2,3,4,5,6,7,11]
##########
frames = pims.ImageSequence('/Users/User/Desktop/eleventh_trial_2/*.tif', as_grey=True)
f1 = tp.locate(frames[0], pixel_min,minmass=min_mass)
plt.figure(1)
ax3=tp.annotate(f1,frames[0])
ax = plt.subplot()
ax.hist(f1['mass'], bins=20)
ax.set(xlabel='mass', ylabel='count');
f = tp.batch(frames[:], pixel_min, minmass=min_mass);
#f = tp.batch(frames[lower_frame:upper_frame], pixel, minmass=min_mass);
t=tp.link_df(f,10,memory=3)
##############
min_mass=8000#12000 #3000#2000 #6000#3000
pixel_min=23;
count=0
img_array = []
for filename in glob.glob('/Users/User/Desktop/eleventh_trial_2/*.tif'):
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
img2 = io.imread(filename, as_gray=True)
fig, ax = plt.subplots()
ax.imshow(img)
#ax=pl.text(T1[i,1]+13,T1[i,0],str(int(T1[i,9])),color="red",fontsize=18)
T1=t.loc[t['frame']==count]
T1=np.array(T1.sort_values(by='particle'))
for i in Selector1:
pl.text(T1[i,1]+13,T1[i,0],str(int(T1[i,9])),color="red",fontsize=18)
circle2 = plt.Circle((T1[i,1], T1[i,0]), 5, color='r', fill=False)
ax.add_artist(circle2)
count=count+1
img_array.append(fig)
ani = animation.ArtistAnimation(fig, img_array, interval=50, blit=True,repeat_delay=1000)
When I run this I don't get an an error however I can't save the ani as tried in the past either using OpenCV videoWriter.
I found a work around although not the most efficient one. I saved the figures in a separate directory using os and plt.savefig() and then use ImageJ to automatically convert the sequentially numbered and saved figures into an animation. It ain't efficient but gets the job done. I am still open to more efficient answers. Thanks
Related
I have an image and I want to filter it to split the text from the background:
and after applying below code:
from skimage import filters
from skimage.filters import threshold_otsu
from skimage import io as skimage_io # So as not to clash with builtin io
dir = r"image_path/a.jpg"
img = skimage_io.imread(dir, as_gray=True, plugin='imageio')
blurred = filters.gaussian(img, sigma=2.0)
sobel = filters.sobel_h(blurred)
blurred += sobel
blurred += sobel
thresh = threshold_otsu(blurred)
# skimage_io.imshow(blurred)
print(thresh)
binary = img < thresh-0.1
skimage_io.imshow(binary)
The image became
Is there a way to make the result better ??
Yes, you can get a better result:
You do account for the noise, but the gaussian blur you apply is much too strong; it starts to dull out the features you are interested in (the letters).
As #Ziri pointed out in a comment, you are not accounting for the uneven exposure that is present in your image. There is many ways to do that; I will use a rolling ball filter to smooth out the background and combine it with a global thresholding method. Note that this is currently (August 2020) a PR in skimage, but will hopefully get merged soon.
import numpy as np
import matplotlib.pyplot as plt
from skimage import util
from skimage import filters
from skimage import io
from skimage import exposure
# PR 4851; will hopefully be in the library soon(TM)
from skimage.morphology import rolling_ellipsoid
img = io.imread("test.jpg", as_gray=True)
img_inv = util.invert(util.img_as_float(img))
# blurr the image slightly to remove noise
blurred = filters.gaussian(img_inv, sigma=1.0)
# remove background
background = rolling_ellipsoid(blurred, kernel_size=(50, 50), intensity_vertex=0.1)
normalized = blurred - background
# re-normalize intensity
normalized = exposure.rescale_intensity(normalized)
# binarize
binary = normalized > 0.38
binary = util.invert(binary)
plt.imshow(binary, cmap="gray")
plt.gca().axis("off")
plt.show()
Sidenote: It may not be wise to upload an uncensored picture of a passport to SO where it is freely accessible to anybody.
I am was trying out one of the sample Python scripts available from the web site of Scikit Image. This script demonstrates Otsu segmentation at a local level. The script works with pictures loaded using
data.page()
but not using
io.imread
. Any suggestions?
https://scikit-image.org/docs/dev/auto_examples/applications/plot_thresholding.html#sphx-glr-auto-examples-applications-plot-thresholding-py
Picture file
Actual output - the Local thresholding window is empty
As you can see, Global thresholding has worked.But Local Thresholding has failed to produce any results.
Strangely, if I use data.page() then everything works fine.
Script
from skimage import io
from skimage.color import rgb2gray
import matplotlib.pyplot as plt
from skimage.filters import threshold_otsu,threshold_local
import matplotlib
from skimage import data
from skimage.util import img_as_ubyte
filename="C:\\Lenna.png"
mypic= img_as_ubyte (io.imread(filename))
#image = data.page() #This works - why not io.imread ?
imagefromfile=io.imread(filename)
image = rgb2gray(imagefromfile)
global_thresh = threshold_otsu(image)
binary_global = image > global_thresh
block_size = 35
local_thresh = threshold_local(image, block_size, offset=10)
binary_local = image > local_thresh
fig, axes = plt.subplots(nrows=3, figsize=(7, 8))
ax = axes.ravel()
plt.gray()
ax[0].imshow(image)
ax[0].set_title('Original')
ax[1].imshow(binary_global)
ax[1].set_title('Global thresholding')
ax[2].imshow(binary_local)
ax[2].set_title('Local thresholding')
for a in ax:
a.axis('off')
plt.show()
If you load the lenna.png and print its shape you will see it is a 4-channel RGBA image rather than a 3-channel RGB image.
print mypic.shape
(512, 512, 4)
I am not sure which parts of your code apply to which image, so I am not sure where to go next, but I guess you want to just get the RGB part and discard the alpha:
RGB = mypic[...,:3]
I am learning image manipulation as a beginner in python. My goal is to section my image into an nxn grid where each square is the average color (greyscale image) of the original, respectively. I succeeded in splitting the image, changing its pixel data and saving the new images. My problem is now stitching the image back together. I know the join function is pointing back to the original image, I had hoped that by saving over the tiles I could work around this.
This is my first time posting to stackoverflow (and I am super, super new to python), so apologies if I am not clear or if the formatting is wrong.
# Import packages
import numpy as np
from numpy import matlib
import PIL
import image_slicer
import math
import glob
from image_slicer import join
from PIL import Image
### Use PIL to import image
##img = Image.open("einstein.jpg")
# Display original image
# img.show()
##new_img = img.resize((256,256))
##new_img.save('einstein-256x256','png')
### new_img.show()
#Slice image into four pieces
tiles = image_slicer.slice("einstein.jpg", 16)
# Use glob to open every .png file with for loop
for filename in glob.glob("*.png"):
img=Image.open(filename)
pixels = img.load() # create the pixel map
pixelMap = img.load() #create the pixel map
#convert to array
arr = np.asarray(img)
#find mean
pixelMean = arr.mean(0).mean(0)[0]
# Convert mean to integer
IntMean = math.floor(pixelMean)
print(IntMean)
##pixel = pixelMap[0,0] #get the first pixel's value
##print(pixel)
# Loop for going through every pixel in image and converting it
for i in range(img.size[0]): # for every col:
for j in range(img.size[1]): # For every row
pixels[i,j] = (IntMean,IntMean,IntMean) # set the colour accordingly
# Save new monotone images
img.save(filename)
# Join new images into one
image = join(tiles)
# Save new image
image.save("einsteinJoined.jpg")
image.show()
Your question seems to be missing the error you get with your current code.
However, if I read it correctly, you will get back your original image, as was the problem in Split and Join images in Python. Similar to the answer accepted there, the solution is to change the image in each tile by ending your loop with:
tile.image = Image.open(filename)
Where tile is the tile corresponding to the file, you should loop over the tiles from the image_slicer.slice-function to do so. This is also given in answer to the question linked to.
from scipy.misc import imread
from matplotlib import pyplot
import cv2
from cv2 import cv
from SRM import SRM ## Module for Statistical Regional Segmentation
im = imread("lena.png")
im2 = cv2.imread("lena.png")
print type(im), type(im2), im.shape, im2.shape
## Prints <type 'numpy.ndarray'> <type 'numpy.ndarray'> (120, 120, 3) (120, 120, 3)
srm = SRM(im, 256)
segmented = srm.run()
srm2 = SRM(im2, 256)
segmented2 = srm2.run()
pic = segmented/256
pic2 = segmented2/256
pyplot.imshow(pic)
pyplot.imsave("onePic.jpg", pic)
pic = pic.astype('uint8')
cv2.imwrite("onePic2.jpg", pic2)
pyplot.show()
onePic.jpg gives the correct segmented image but onePic2.jpg gives a complete black image.
Converting the datatype to uint8 using pic = pic.astype('uint8') did not help. I still gives a black image!
onePic.jpg using pyplot.imsave():
onePic2.jpg using cv2.imwrite():
Please help!
Before converting pic to uint8, you need to multiply it by 255 to get the correct range.
Although I agree with #sansuiso, in my case I found a possible edge case where my images were being shifted either one bit up in the scale or one bit down.
Since we're dealing with unsigned ints, a single shift means a possible underflow/overflow, and this can corrupt the whole image.
I found cv2's convertScaleAbs with an alpha value of 255.0 to yield better results.
def write_image(path, img):
# img = img*(2**16-1)
# img = img.astype(np.uint16)
# img = img.astype(np.uint8)
img = cv.convertScaleAbs(img, alpha=(255.0))
cv.imwrite(path, img)
This answer goes into more detail.
I encountered a similar situation with face detection, I wonder if there is a better way to execute this, here is my solution here as a reference.
from deepface import DeepFace
import cv2
import matplotlib.pyplot as plt
# import image and output
img_path = "image.jpg"
detected_face = DeepFace.detectFace(img_path, target_size = (128, 128))
plt.imshow(detected_face)
# image color scaling and saving
detected_face = cv2.cvtColor( detected_face,cv2.COLOR_BGR2RGB)
detected_face = cv2.convertScaleAbs(detected_face, alpha=(255.0))
cv2.imwrite("image_thumbnail.jpg", detected_face)
Is it possible to have black-and-white and color image on same window by using opencv libraray? How can I have both of these images on same window?
fraxel's answer has solved the problem with old cv interface. I would like to show it using cv2 interface, just to understand how this easy in new cv2 module. (May be it would be helpful for future visitors). Below is the code:
import cv2
import numpy as np
im = cv2.imread('kick.jpg')
img = cv2.imread('kick.jpg',0)
# Convert grayscale image to 3-channel image,so that they can be stacked together
imgc = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
both = np.hstack((im,imgc))
cv2.imshow('imgc',both)
cv2.waitKey(0)
cv2.destroyAllWindows()
And below is the output I got:
Yes it is, here is an example, expaination in the comments:
import cv
#open color and b/w images
im = cv.LoadImageM('1_tree_small.jpg')
im2 = cv.LoadImageM('1_tree_small.jpg',cv.CV_LOAD_IMAGE_GRAYSCALE)
#set up our output and b/w in rgb space arrays:
bw = cv.CreateImage((im.width,im.height), cv.IPL_DEPTH_8U, 3)
new = cv.CreateImage((im.width*2,im.height), cv.IPL_DEPTH_8U, 3)
#create a b/w image in rgb space
cv.Merge(im2, im2, im2, None, bw)
#set up and add the color image to the left half of our output image
cv.SetImageROI(new, (0,0,im.width,im.height))
cv.Add(new, im, new)
#set up and add the b/w image to the right half of output image
cv.SetImageROI(new, (im.width,0,im.width,im.height))
cv.Add(new, bw, new)
cv.ResetImageROI(new)
cv.ShowImage('double', new)
cv.SaveImage('double.jpg', new)
cv.WaitKey(0)
Its in python, but easy to convert to whatever..
Small improvement to the code with modern writing
concatenate
instead of
hstack
that is discontinued (stack can also be used)
import cv2
import numpy as np
im = cv2.imread('kick.jpg')
img = cv2.imread('kick.jpg',0)
# Convert grayscale image to 3-channel image,so that they can be stacked together
imgc = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
both = np.concatenate((im,imgc), axis=1) #1 : horz, 0 : Vert.
cv2.imshow('imgc',both)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
img = cv2.imread("image.jpg" , cv2.IMREAD_GRAYSCALE)
cv2.imshow("my image",img)
cv2.waitkey(0)
cv2.destroyAllWindow
#The image file should be in the application folder.
#The output file will be 'my image' name.
#The bottom line is to free up memory.