saving random images in separate folder in python - python

I am facing a little problem,
actually I have a function which generates so many frames from a video that I provided to my code which then saves in a specific folder , then I access some frames from that folder by using RND (random ) command , now what I want is that those random frames which my code pick randomly should also save in some other folder, for example, if there are 300 frames and my code pick 15 frames randomly from those 300 frames then these 15 frames must also save in some other separate folder .
This is my code,
def video_frames(nameof_video,frame_savelocation,cropimages_save):
vidcap = cv2.VideoCapture(nameof_video)
success, image = vidcap.read()
print(success)
count = 1
success = True
while success:
success, image = vidcap.read()
cv2.imwrite(frame_savelocation+"/%d.jpg" % count, image)
# save frame as JPEG file
# if cv2.waitKey(10) == 27: # exit if Escape is hit
# break
if count == 0:
break
count += 1
print("frames saved in the desired location!!!!!")
##### crop faces from frame and save them----###
for r in range(1, 15):
random_imagecrop(frame_savelocation, cropimages_save) #-----> function called
return
def random_imagecrop(frame_savelocation,cropimages_save):
#b=1
crop_faces_path = frame_savelocation
list_frames = os.listdir(crop_faces_path) # dir is your directory path
number_files = len(list_frames)
rnd = random.randint(1, number_files)
print("random:", rnd)
image = face_recognition.load_image_file(frame_savelocation + "/" + str(rnd) + ".jpg")
#pil_image.save("Datasets/randomimg" + "/" + str(b) + ".jpg")
#b=b+1
# Find all the faces in the image
face_locations = face_recognition.face_locations(image)
check = os.listdir(cropimages_save) # dir is your directory path
already_prsntimg = len(check)
a = 1+already_prsntimg
for face_location in face_locations:
# Print the location of each face in this image
top, right, bottom, left = face_location
# print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
# You can access the actual face itself like this:
face_image = image[top:bottom, left:right]
pil_image = Image.fromarray(face_image)
# pil_image.show()
pil_image.save(cropimages_save + "/" + str(a) + ".jpg")
a = a + 1
print("--> Images saved successfully...!!!")
# a=a+len(face_locations)
return

You can use os.chdir('output') to change the working directory to the output directory and then write the image. Then to return to the original directory to pick your random images use os.chdir('../').

Related

How do you save the images that are embedded in the placeholders of a pptx file using python?

I can extract all the images from the shapes of a slide, as shown in the code below. The problem comes when an image is embedded in a placeholder. I have no idea how to get the images from those placeholders, and the documentation to me isn't clear.
Note also that I have a minimum width limit for the kind of images I want, hence I have "shape.width > 250000" in the code
import os
import pptx
from pptx.enum.shapes import MSO_SHAPE_TYPE
ppFileName = "Test.pptx"
directory = os.path.dirname(__file__)
imageDirectory = directory + "\\Images " + ppFileName.replace(".pptx","")
if not os.path.exists(imageDirectory):
os.makedirs(imageDirectory)
def saveImage(shape,slideNumber,imageNumber):
image = shape.image
imageBytes = image.blob
imageFileName = f"Slide {slideNumber} Image {imageNumber}.{image.ext}"
imagePath = imageDirectory + "\\" + imageFileName
with open(imagePath, 'wb') as file:
file.write(imageBytes)
imageNumber += 1
prs = pptx.Presentation(directory + "\\" + ppFileName)
slides = prs.slides
slideNumber = 0
for slide in slides:
imageNumber = 0
for shape in slide.shapes:
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE and shape.width > 250000:
saveImage(shape,slideNumber,imageNumber)
elif shape.shape_type == MSO_SHAPE_TYPE.GROUP and shape.width > 250000:
for s in shape.shapes:
saveImage(s,slideNumber,imageNumber)
slideNumber += 1
Alright, I figured it out.
Just added these three lines of code:
for shape in slide.placeholders:
if hasattr(shape, "image") and shape.width > 250000:
saveImage(shape,slideNumber,imageNumber)

Convert Video to Frames in Python - 1 FPS

I have a video that is 30 fps.
I need to extract frames from the video at 1 FPS. How is this possible in Python?
I have the below code I got from online but I am not sure if its extracting frames in 1 FPS.
Please help!
# Importing all necessary libraries
import cv2
import os
# Read the video from specified path
cam = cv2.VideoCapture("C:\\Users\\Admin\\PycharmProjects\\project_1\\openCV.mp4")
try:
# creating a folder named data
if not os.path.exists('data'):
os.makedirs('data')
# if not created then raise error
except OSError:
print ('Error: Creating directory of data')
# frame
currentframe = 0
while(True):
# reading from frame
ret,frame = cam.read()
if ret:
# if video is still left continue creating images
name = './data/frame' + str(currentframe) + '.jpg'
print ('Creating...' + name)
# writing the extracted images
cv2.imwrite(name, frame)
# increasing counter so that it will
# show how many frames are created
currentframe += 1
else:
break
# Release all space and windows once done
cam.release()
cv2.destroyAllWindows()
KPS = 1# Target Keyframes Per Second
VIDEO_PATH = "video1.avi"#"path/to/video/folder" # Change this
IMAGE_PATH = "images/"#"path/to/image/folder" # ...and this
EXTENSION = ".png"
cap = cv2.VideoCapture(VIDEO_PATH)
fps = round(cap.get(cv2.CAP_PROP_FPS))
print(fps)
# exit()
hop = round(fps / KPS)
curr_frame = 0
while(True):
ret, frame = cap.read()
ifnot ret: break
if curr_frame % hop == 0:
name = IMAGE_PATH + "_" + str(curr_frame) + EXTENSION
cv2.imwrite(name, frame)
curr_frame += 1
cap.release()
This is the code I use when I need to extract frames from videos:
# pip install opencv-python
import cv2
import numpy as np
# video.mp4 is a video of 9 seconds
filename = "video.mp4"
cap = cv2.VideoCapture(filename)
cap.set(cv2.CAP_PROP_POS_AVI_RATIO,0)
frameCount = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frameWidth = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frameHeight = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
videoFPS = int(cap.get(cv2.CAP_PROP_FPS))
print (f"frameCount: {frameCount}")
print (f"frameWidth: {frameWidth}")
print (f"frameHeight: {frameHeight}")
print (f"videoFPS: {videoFPS}")
buf = np.empty((
frameCount,
frameHeight,
frameWidth,
3), np.dtype('uint8'))
fc = 0
ret = True
while (fc < frameCount):
ret, buf[fc] = cap.read()
fc += 1
cap.release()
videoArray = buf
print (f"DURATION: {frameCount/videoFPS}")
You can see how to extract features of the video like frameCount, frameWidth, frameHeight, videoFPS
At the end, the duration should be the number of frames divided by the videoFPS variable.
All the frames are stored inside buf, so if you want to extract only 1 Frame iterate over buf and extract only 9 frames (increasing your video FPS each iteration).
Here's the code that I found works best.
import os
import cv2
import moviepy.editor
def getFrames(vid, output, rate=0.5, frameName='frame'):
vidcap = cv2.VideoCapture(vid)
clip = moviepy.editor.VideoFileClip(vid)
seconds = clip.duration
print('durration: ' + str(seconds))
count = 0
frame = 0
if not os.path.isdir(output):
os.mkdir(output)
success = True
while success:
vidcap.set(cv2.CAP_PROP_POS_MSEC,frame*1000)
success,image = vidcap.read()
## Stop when last frame is identified
print(frame)
if frame > seconds or not success:
break
print('extracting frame ' + frameName + '-%d.png' % count)
name = output + '/' + frameName + '-%d.png' % count # save frame as PNG file
cv2.imwrite(name, image)
frame += rate
count += 1
The value for the rate argument is 1/fps

Data of 1 folder gets added to another

I have a small script which checks if my object is present in image or not. If present then it writes the image to a folder.There are multiple sub-folders inside.On writing, the data for 1st folder works fine but when data is written to the 2nd sub-folder then the data of 1st folder is also appended along-with the data of 2nd folder
The code works perfectly fine except the problem that while writing the data to disk the data of 1st sub-folder is also appended to the data of 2nd sub-folder. Below is my code
def target_non_target(input_frames_folder,model_file,output):
if not os.path.exists(output):
os.makedirs(output,exist_ok=True)
count=0
folders = glob(input_frames_folder)
img_list = []
for folder in folders:
folder_name=os.path.basename(folder)
#print(folder_name)
out_path = output +"\\" + folder_name
print(out_path)
os.makedirs(out_path,exist_ok=True)
for f in glob(folder+"/*.jpg"):
img_list.append(f)
for i in range(len(img_list)):
v1=os.path.basename(img_list[i])
img_name = os.path.splitext(v1)[0]
image = cv2.imread(img_list[i])
orig = image.copy()
image = cv2.resize(image, (28, 28))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
print("[INFO] loading network...")
model = load_model(model_file)
(non_target, target) = model.predict(image)[0]
if target > non_target:
label = "Target"
else:
label = "Non Target"
probab = target if target > non_target else non_target
label = "{}: {:.2f}%".format(label, probab * 100)
op = imutils.resize(orig, width=400)
cv2.putText(op, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX,0.7, (0, 255, 0), 2)
if target > non_target:
cv2.imwrite(out_path+"/"+"\\{}.jpg".format(img_name),orig)
cv2.waitKey(0)
#return target_op
frames_folder = ("C:\\Python36\\videos\\videos_new\\*")
model = ("C:\\Python35\\target_non_target\\target_non_target.model")
output_folder = ("C:\\Python35\\target_non_target\\Target_images_new\\")
target_check = target_non_target(frames_folder,model,output_folder)
Suppose there are 2 sub-folders A and B inside a main folder X.There will be many more sub-folders.While writing output to disk the data of A is written perfectly but while writing data for B the data of folder A and folder B both are getting appended into B folder. I want the data to be in their respective folders. Any idea what changes could be made in my script for getting the desired output
You are using the img_list = [] to initiate but you need to repeat this at the end of each folder loop to reset it back to empty. Right now you are keeping all of your results and then when you move to the next folder you are keeping your previous results and adding on.
The very end of your for folder in folders loop needs to have img_list = []
Updated full code:
def target_non_target(input_frames_folder,model_file,output):
if not os.path.exists(output):
os.makedirs(output,exist_ok=True)
count=0
folders = glob(input_frames_folder)
img_list = []
for folder in folders:
folder_name=os.path.basename(folder)
#print(folder_name)
out_path = output +"\\" + folder_name
print(out_path)
os.makedirs(out_path,exist_ok=True)
for f in glob(folder+"/*.jpg"):
img_list.append(f)
for i in range(len(img_list)):
v1=os.path.basename(img_list[i])
img_name = os.path.splitext(v1)[0]
image = cv2.imread(img_list[i])
orig = image.copy()
image = cv2.resize(image, (28, 28))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
print("[INFO] loading network...")
model = load_model(model_file)
(non_target, target) = model.predict(image)[0]
if target > non_target:
label = "Target"
else:
label = "Non Target"
probab = target if target > non_target else non_target
label = "{}: {:.2f}%".format(label, probab * 100)
op = imutils.resize(orig, width=400)
cv2.putText(op, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX,0.7, (0, 255, 0), 2)
if target > non_target:
cv2.imwrite(out_path+"/"+"\\{}.jpg".format(img_name),orig)
cv2.waitKey(0)
img_list = [] # this is the end of for folder in folders, reset list
#return target_op
frames_folder = ("C:\\Python36\\videos\\videos_new\\*")
model = ("C:\\Python35\\target_non_target\\target_non_target.model")
output_folder = ("C:\\Python35\\target_non_target\\Target_images_new\\")
target_check = target_non_target(frames_folder,model,output_folder)

Combine files using Pillow and Python

I need to run a python script inside a folder.
the script count files ( image ) number create an image for
every 64 images.
example: if the folder containing 640 images, I will get 10
images as a combination of 64 images/outputimage
just, before adding "for" instruction, I can get a result, but manually and only with the same image ( a duplication of image ).
any idea?
so I proceed as follows:
import os
import os.path
from PIL import Image
list = os.listdir(".") # current directory
number_files = len(list)
print (number_files)
for x in range(0, number_files):
# files = ['x.png']
# opens an image: here I can't find how
im = Image.open("1.png") # here I tried to
# creates a new empty image, RGB mode, and size 800 by 800.
new_im = Image.new('RGB', (800, 800))
# Here I resize my opened image, so it is no bigger than 100,100
im.thumbnail((100, 100))
# Iterate through a 8 by 8 grid with 100 spacing, to place my image
for i in xrange(0, 800, 100):
for j in xrange(0, 800, 100):
# paste the image at location i,j:
new_im.paste(im, (i, j))
new_im.save(os.path.expanduser('outputimage.png'))
update :
import os
import os.path
from PIL import Image
def drange(start, stop, step):
while start < stop:
yield start
start += step
list = os.listdir(".") # directory path
number_files = len(list)
print (number_files)
new_im = Image.new('RGB', (800, 800))
for x in drange(0, number_files, 64):
im = Image.open(list[x])
im.thumbnail((100, 100))
for i in xrange(0, 800, 100):
for j in xrange(0, 800, 100):
new_im.paste(im, (i, j))
new_im.save(os.path.expanduser('out.png'))
other update based on Sven solution :
import os.path
from PIL import Image
fileList = [] where_to_look = "png/"
for f in os.listdir(where_to_look):
if os.path.isfile(os.path.join(where_to_look, f)):
fileList.append(f)
print (len(fileList))
target_img = None n_targets = 0 collage_saved = False
for n in range(len(fileList)):
img = Image.open(fileList[n])
img.thumbnail((100, 100))
if n % 64 == 0:
# create an empty image for a collage
target_img = Image.new("RGB", (800, 800))
n_targets += 1
collage_saved = False
# paste the image at the correct position
i = int(n / 8)
j = n % 8
target_img.paste(img, (100*i, 100*j))
if (n + 1) % 64 == 0 and target_img is not None:
# save a finished 8x8 collage
target_img.save("{0:04}.png".format(n_targets))
collage_saved = True
# save the last collage if not collage_saved:
target_img.save("{0:04}.png".format(n_targets))
Based on your update, I quickly sketched a solution. Please beware that I did not test it:
import os
from PIL import Image
image_dir = os.path.abspath("png")
# list all files in directory
files = os.listdir(image_dir)
# get all PNGs
png_files = filter(lambda x: x.endswith(".png"), files)
# make file paths absolute
image_files = map(lambda x: os.sep.join([image_dir, x]), png_files)
n_files = len(image_files)
target_img = None
n_targets = 0
collage_saved = False
for n in range(n_files):
img = Image.open(image_files[n])
img.thumbnail((100, 100))
if n % 64 == 0:
# create an empty image for a collage
target_img = Image.new("RGB", (800, 800))
n_targets += 1
collage_saved = False
# paste the image at the correct position
i = int(n / 8)
j = n % 8
target_img.paste(img, (100*i, 100*j))
if (n + 1) % 64 == 0 and target_img is not None:
# save a finished 8x8 collage
target_img.save("{0:04}.png".format(n_targets))
collage_saved = True
# save the last collage
if not collage_saved:
target_img.save("{0:04}.png".format(n_targets))
This will iterate over all your images and assemble them in a 8x8 grid (I call it collage in the script). Whenever the grid is filled, the collage is saved as a file with the naming pattern 0001.png, 0002.png and so on.
Note that there are some points to improve:
os.listdir(".") will give you all files in the directory, not only images. You would have to filter the output for image files.
This only works in the current working directory.
The output is also saved to the current working directory.
UPDATE: filter PNGs and use absolute paths

Python PIL - Resizing Images Without Keeping Aspect Ratio

So I've got a Python script that takes a bunch of images in a folder, and puts them together into arrays (like this). I also have another script that takes the frames of a video and puts them together in arrays. The problem is, the one that takes the frames from a video creates black bars between the images.
Here is the correct image made using the first script, which uses JPEGS:
Here is the wrong image made using the second script, which uses video frames:
Here is the script that makes the correct first image:
import Image
import glob
import os
name = raw_input('What is the file name (excluding the extension) of your video that was converted using FreeVideoToJPGConverter?\n')
x_res = int(raw_input('What do you want the width of your image to be (in pixels)?\n'))
y_res = int(raw_input('What do you want the height of your image to be (in pixels)?\n'))
rows = int(raw_input('How many rows do you want?\n'))
columns = int(raw_input('How many columns do you want?\n'))
images = glob.glob('./' + name + ' (*)/' + name + '*.jpg')
new_im = Image.new('RGB', (x_res,y_res))
x_cntr = 0
y_cntr = 0
if not os.path.exists('./' + name + ' Output/'):
os.makedirs('./' + name + ' Output/')
for x in xrange(0,len(images),1):
if x%(rows*columns) == 0:
new_im.save('./' + name + ' Output/' + str(x) + '.jpg')
new_im = Image.new('RGB', (x_res,y_res))
y_cntr = 0
x_cntr = 0
print str(round(100*(float(x)/len(images)), 1)) + "% Complete"
elif x%rows == 0:
x_cntr = 0
y_cntr = y_cntr + y_res/columns
elif x%1 == 0:
x_cntr = x_cntr + x_res/rows
im = Image.open(images[x])
im = im.resize((x_res/rows + x_res%rows, y_res/columns + y_res%columns), Image.ANTIALIAS)
new_im.paste(im, (x_cntr, y_cntr))
Here is the script that makes the incorrect second image:
import cv2, Image, os
name = raw_input('Video File (With Extension): ')
x_res = int(raw_input('Image Width (Pixels): '))
y_res = int(raw_input('Image Height (Pixels): '))
rows = int(raw_input('Number of Rows: '))
columns = int(raw_input('Number of Columns: '))
vidcap = cv2.VideoCapture(name)
success,im = vidcap.read()
frames = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT))
new_im = Image.new('RGB', (x_res, y_res))
x_cntr = 0
y_cntr = 0
print str(frames) + " Frames to Join"
if not os.path.exists('./' + name + ' Output/'):
os.makedirs('./' + name + ' Output/')
for x in xrange(0,frames,1):
if x%(rows*columns) == 0:
new_im.save('./' + name + ' Output/' + str(x) + '.jpg')
new_im = Image.new('RGB', (x_res,y_res))
y_cntr = 0
x_cntr = 0
print str(round(100*(float(x)/frames), 1)) + "% Complete"
elif x%rows == 0:
x_cntr = 0
y_cntr = y_cntr + y_res/columns
elif x%1 == 0:
x_cntr = x_cntr + x_res/rows
success,cv2_im = vidcap.read()
if success == True:
cv2_im = cv2.cvtColor(cv2_im,cv2.COLOR_BGR2RGB)
im = Image.fromarray(cv2_im)
im = im.resize((x_res/rows + x_res%rows, y_res/columns + y_res%columns), Image.ANTIALIAS)
new_im.paste(im, (x_cntr, y_cntr))
elif success == False:
new_im.save('./' + name + ' Output/' + str(x) + '.jpg')
print str(round(100*(float(x)/frames), 1)) + "% Complete" #Why isn't this 100%, fix
As you can see, this specific line for resizing the image (to fit the new array of images) is exactly the same in both scripts:
im = im.resize((x_res/rows + x_res%rows, y_res/columns + y_res%columns), Image.ANTIALIAS)
...Except in the first script, the image is opened from a JPEG, and in the second script, the image is taken from a video frame using OpenCV2. If I try this with a different video, the same thing happens. It resizes as if I were using .thumbnail instead of .resize.
So why is there a different output even though they are the same script?
PS: I also don't know why there are more output images on the jpeg script than the video script, but that may be the fault of FreeVideoToJPGConverter (a software); I'm not sure though.

Categories

Resources