The context of my Computer Vision assignment: Computing a homography matrix, where one of the tasks is to create a GUI to select points on the images (to get the coordinates, and pixel values).
I've looked through StackOverflow and found some options, i.e using tkinter, but the answers were from 2011. I was wondering whether there are other or new options out there.
Here is the code that worked for me using openCV 3.3.1
For camera calibration see my github repo https://github.com/abhishek098/camera_calibration .
import numpy as np
import yaml
import cv2
'''
1. change the path to load image and store data
2. double click on the image to save the co-ordinates
3. images should be named as 0.jpg, 1.jpg, 2.jpg .....
4.
'''
# set image and data path here..
path = "/home/abhishek/stuff/object_detection/explore/"
points = []
def mouseCB(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK :
print (x, y)
points.append([x, y])
count = 0
exit_flag = True
points_list = []
while exit_flag:
window_name = 'image_' + str(count)
cv2.namedWindow(window_name)
cv2.setMouseCallback(window_name, mouseCB)
image_name = path + str(count) + '.jpg'
img = cv2.imread(image_name)
cv2.imshow(window_name, img)
while True:
ip = cv2.waitKey(0) & 0xFF
if ip == ord('n'):
count += 1
points_list.append(points)
points = []
cv2.destroyAllWindows()
break
elif ip == ord('q'):
exit_flag = False
break
print (count)
data = {'img_co': np.asarray(points_list).tolist()}
file = path + "data.yaml"
with open(file, "w") as f:
yaml.dump(data, f)
cv2.destroyAllWindows()
Related
This is my code, It takes a picture via webcam and saves it in a folder I specify. The name is then "day-time_0/1/2/3.jpg".
The problem is I would like to have it without "_0/1/2/3". But these numbers are necessary for the loop I think at least. But if I take out this count it saves a picture and over saves it every time I want to make another picture in the same interface.
Is there a way that if I am in the same interface and take several pictures that I can save them again and again with the new current time?
import cv2
import os
import time
timestr = time.strftime("%Y%m%d-%H%M%S")
def save_frame_camera_key(device_num, dir_path, basename, ext='jpg', delay=1, window_name='frame'):
cap = cv2.VideoCapture(device_num)
if not cap.isOpened():
return
os.makedirs(dir_path, exist_ok=True)
base_path = os.path.join(dir_path, basename)
n = 0
while True:
ret, frame = cap.read()
cv2.imshow(window_name, frame)
key = cv2.waitKey(delay) & 0xFF
if key == ord('c'):
cv2.imwrite('{}_{}.{}'.format(base_path, **n**, ext), frame)
** n += 1**
elif key == ord('q'):
break
cv2.destroyWindow(window_name)
save_frame_camera_key(0, 'data/temp', timestr)
As i said i tried deleting the count. Didnt work. Ive tried it with an different capture Code and it didnt work.
i am trying to do a program where it detects the video and capture every 100th frame then display the output. the problem that i faced here is that there will be duplication for example, the current pattern for the output is (1,1,1,2,2,3,3,2,1) but the result that i want to show is (1,2,3,2,1). To sum up, not displaying the same text continuously but allowed to be displayed when the previous image is different with the current ones. I have tried coming up with an idea of removing duplicate images but it will not give the expected result as it will delete all the images.
from PIL import Image
import pytesseract
from wand.image import Image as Img
import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
import numpy as np
import os
import cv2
image_frames = 'image_frames'
def files():
#auto create image frames file
try:
os.remove(image_frames)
except OSError:
pass
if not os.path.exists(image_frames):
os.makedirs(image_frames)
# specify the source video path
src_vid = cv2.VideoCapture('15sec.mp4')
return(src_vid)
def process(src_vid):
# Use an index to integer-name the files
index = 0
while (src_vid.isOpened()):
ret, frame = src_vid.read()
if not ret:
break
# name each frame and save as png / jpeg
name = './image_frames/frame' + str(index) + '.jpeg'
if index % 100 == 0:
print('Extracting frames...' + name)
cv2.imwrite(name, frame)
index = index + 1
if cv2.waitKey(10) & 0xFF == ord('q'):
break
src_vid.release()
cv2.destroyAllWindows()
# do image to text on each png
def get_text():
for i in os.listdir(image_frames):
print(str(i))
my_image = Image.open(image_frames + "/" + i)
pytesseract.pytesseract.tesseract_cmd = r'C:\Users\USERS\AppData\Local\Tesseract-OCR\tesseract.exe'
text = pytesseract.image_to_string(my_image, lang='eng')
print(text)
# main driver
if __name__ == '__main__':
vid = files()
process(vid)
get_text()
everyone.
I'm a struggling freshman for programming.
I'll really appreciate any of your help or advice.
I want to make this code do these jobs.
Read video files in specific folder.
Extract frame image from this video file
Save them in specific folder(ex. from video_1.mp4, make folder video_1_frameimage and save images video_1_frame0, video_1_frame300, ..... and so on into this specific folder)
To make this function I made this code but it doesn't work that nicely.
Thank you for reading my question!
import cv2
import os
path_for_video = "C:/Users/정지원/Desktop/Video_files"
video_list = os.listdir(path_for_video)
for video_file in video_list:
file_path= os.path.join(path_for_video,video_file)
cap = cv2.VideoCapture(file_path)
index = 0
while (True):
ret, frame = cap.read()
if ret == False:
break
if index % 300 == 0:
name = video_file + '_frame' + str(index) + '.jpg'
print('Creating...' + name)
if not os.path.exists('C:/Users/정지원/Desktop/Video_files/'+ video_file):
os.makedirs('C:/Users/정지원/Desktop/Video_files/' + video_file)
path_for_image = 'C:/Users/정지원/Desktop/Video_files/' + video_file
cv2.imwrite(os.path.join(path_for_image, name), frame)
index += 1
cap.release()
cv2.destroyAllWindows()
The idea is that, user should be able to load a video from their local machine and tell the program to take a screenshot from the video every 5sec or 30sec. Is there any library to help me with this task? Any idea from how to proceed would be helpful.
install opencv-python (which is an unofficial pre-built OpenCV package for Python) by issuing the following command:
pip install opencv-python
# Importing all necessary libraries
import cv2
import os
import time
# Read the video from specified path
cam = cv2.VideoCapture("C:/Users/User/Desktop/videoplayback.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):
time.sleep(5) # take schreenshot every 5 seconds
# 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()
the above answer is partially right but time.sleep here does not help at all but rather it makes the process slower. however, if you want to take a screenshot at a certain time of a video you need to understand that every time you do "ret, frame = cam.read()" it reads the next frame of the video. every second in a video has a number of frames depends on the video. you get that number using:
frame_per_second = cam.get(cv2.CAP_PROP_FPS)
so if you need to take a screenshot of the 3rd second you can keep the iteration as is in the above answer and just add
if currentframe == (3*frame_per_second):
cv2.imwrite(name, frame)
this will take a screenshot of the first frame in the 3rd second.
#ncica & Data_sniffer solution remake
import cv2
import os
import time
step = 10
frames_count = 3
cam = cv2.VideoCapture('video/example.MP4')
currentframe = 0
frame_per_second = cam.get(cv2.CAP_PROP_FPS)
frames_captured = 0
while (True):
ret, frame = cam.read()
if ret:
if currentframe > (step*frame_per_second):
currentframe = 0
name = 'photo/frame' + str(frames_captured) + '.jpg'
print(name)
cv2.imwrite(name, frame)
frames_captured+=1
if frames_captured>frames_count-1:
ret = False
currentframe += 1
if ret==False:
break
cam.release()
cv2.destroyAllWindows()
#a generic function incorporating all the comments mentioned above.
def get_frames(inputFile,outputFolder,step,count):
'''
Input:
inputFile - name of the input file with directoy
outputFolder - name and path of the folder to save the results
step - time lapse between each step (in seconds)
count - number of screenshots
Output:
'count' number of screenshots that are 'step' seconds apart created from video 'inputFile' and stored in folder 'outputFolder'
Function Call:
get_frames("test.mp4", 'data', 10, 10)
'''
#initializing local variables
step = step
frames_count = count
currentframe = 0
frames_captured = 0
#creating a folder
try:
# creating a folder named data
if not os.path.exists(outputFolder):
os.makedirs(outputFolder)
#if not created then raise error
except OSError:
print ('Error! Could not create a directory')
#reading the video from specified path
cam = cv2.VideoCapture(inputFile)
#reading the number of frames at that particular second
frame_per_second = cam.get(cv2.CAP_PROP_FPS)
while (True):
ret, frame = cam.read()
if ret:
if currentframe > (step*frame_per_second):
currentframe = 0
#saving the frames (screenshots)
name = './data/frame' + str(frames_captured) + '.jpg'
print ('Creating...' + name)
cv2.imwrite(name, frame)
frames_captured+=1
#breaking the loop when count achieved
if frames_captured > frames_count-1:
ret = False
currentframe += 1
if ret == False:
break
#Releasing all space and windows once done
cam.release()
cv2.destroyAllWindows()
To add on data_sniffer's answer. I would recommend using round (Math function) on frame_per_second when checking as if the frame rate is a decimal number then it will go into an infinite loop.
The solutions provided do not work for me in several cases.
The FPS from cv2.CAP_PROP_FPS is a floating point value and the FPS rate of my testvid.mp4 was 23.976023976023978 according to this property.
When looping through current_frame / fps % 3, we will almost always have leftovers because of this floating point value. Same goes for (3*frame_per_second):, causing our imwrite to never be reached.
I solved this issue by using the same calculations, but storing the remainders and comparing those:
current_frame = 0
fps_calculator_previous = 0
while (True):
ret, frame = cam.read()
if ret:
# Still got video left.
file_name = f"./data_generation/out/{_fn}-{current_frame}.jpg"
fps_calculator = (current_frame / fps) % every_x_sec
if(fps_calculator - fps_calculator_previous < 0):
print("Found a frame to write!")
cv2.imwrite(file_name, frame)
fps_calculator_previous = fps_calculator
current_frame += 1
else:
break
This seems to work well for me with any value for both cv2.CAP_PROP_FPS as well as every_x_sec
My video was 18 minutes and 7 seconds long, and I captured 362 unique frames from that with every_x_sec set to 3.
Edited #ncica's code and noted that it is working fine.
import cv2
import os
import time
cam = cv2.VideoCapture("/path/to/videoIn.mp4")
try:
if not os.path.exists('data'):
os.makedirs('data')
except OSError:
print('Error: Creating directory of data')
intvl = 2 #interval in second(s)
fps= int(cam.get(cv2.CAP_PROP_FPS))
print("fps : " ,fps)
currentframe = 0
while (True):
ret, frame = cam.read()
if ret:
if(currentframe % (fps*intvl) == 0):
name = './data/frame' + str(currentframe) + '.jpg'
print('Creating...' + name)
cv2.imwrite(name, frame)
currentframe += 1
else:
break
cam.release()
cv2.destroyAllWindows()
The trick is it is looping frame-by-frame.
So, here we are capturing frames that we want and write disk as snapshot image file.
eg : If you want snapshot two second by two second intvl must be 2
I wrote a Python program with OpenCV that:
scans the folder with images
does some operations on them with respect to their order
returns a list IMGs of processed images
Now what I want to do, is to save the list IMGs of new pictures as a e.g. .avi movie. How to do such operation? I intentionally want to save pictures from a list after whole process of filtration etc.
import os
import cv2
import numpy as np
folder_name = 'trial1'
extension = '.bmp'
path = os.getcwd()
GB_kernel = (13,13)
""" List all .bmp images names from a folder """
def folder_content(folder_name, extension):
dir_content = os.listdir(folder_name)
folder_content_ext = []
for file in dir_content:
if file.endswith(extension):
folder_content_ext.append(file)
return folder_content_ext
IMG_names = folder_content(folder_name, extension)
""" Some OpenCV operations on images """
""" Loop over all images. Iterator i is important in the future """
IMGs = []
for i in range(len(IMG_names)):
""" Define path to basic image """
img = path + '\\' + folder_name + '\\' + IMG_names[i]
""" read this image """
image = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
""" some operation - gaussian blur """
pre_filt = cv2.GaussianBlur(image, GB_kernel, 0)
""" contain blurred img in a list """
IMGs.append(pre_filt)
cv2.imshow('Gaussian Blur', pre_filt)
WKey = 1
if cv2.waitKey(WKey) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
""" HOW?? """
save_list_of_matrix_as_movie(IMGs)
Thanks for any help and hints.
You can try the code below.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Create video from images in a list.
Idea from:
http://tsaith.github.io/combine-images-into-a-video-with-python-3-and-opencv-3.html
"""
import os
import time
import cv2
folder_name = 'trial1'
extension = '.bmp'
video_file = 'out.avi'
path = os.getcwd()
GB_kernel = (13, 13)
# %%
def folder_content():
"""
List all images names with given extension from a folder.
"""
dir_content = os.listdir(folder_name)
folder_content_ext = []
for file in dir_content:
if file.endswith(extension):
folder_content_ext.append(file)
return folder_content_ext
# %%
def img_2_matrix(img_names):
"""
Some OpenCV operations on images
Loop over all images. Iterator i is important in the future
"""
imgs = []
for i in range(len(img_names)):
# Define path to basic image
img = os.path.join(path, folder_name, img_names[i])
# read this image
image = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
# some operation - gaussian blur
pre_filt = cv2.GaussianBlur(image, GB_kernel, 0)
# contain blurred img in a list
imgs.append(pre_filt)
cv2.imshow('Gaussian Blur', pre_filt)
wkey = 1
if cv2.waitKey(wkey) & 0xFF == ord('q'):
break
return imgs
# %%
def save_list_of_matrix_as_movie(imgs):
"""
"""
shape = (imgs[0].shape[1], imgs[0].shape[0])
fourcc = cv2.VideoWriter_fourcc(*"XVID") # XVID for avi, mp4v for mp4
out = cv2.VideoWriter(video_file, fourcc, 20.0, shape, 0)
print("\nHit 'q' to exit")
for frame in imgs:
pre_filt = cv2.GaussianBlur(frame, GB_kernel, 0)
out.write(pre_filt) # Write out frame to video
cv2.imshow("video", pre_filt)
if(cv2.waitKey(1) & 0xFF) == ord("q"): # Hit `q` to exit
break
return out
# %%
def release(out):
"""
Release everything if job is finished
"""
cv2.destroyAllWindows()
out.release()
# %%
if __name__ == "__main__":
# %%
TIC = time.time()
# %%
img_names = folder_content()
imgs = img_2_matrix(img_names)
out = save_list_of_matrix_as_movie(imgs)
release(out)
# %%
print("Time elapsed: %0.2f s" % (time.time() - TIC))