Olej писал(а):Возникла такая интересная задача... :
Продолжение задачи...
- нужно из видеопотока нарезать отдельные изображения лиц, для заполнения каталога эталонных изображений в распознавании лиц...
- видеопотоком может быть, на выбор, альтернативно: а). WEB камера, одна из нескольких на выбор, б). записанный видеофайл .avi/.mkv, в). каталог с линейным набором файлов-картинок .jpg/.png/.gif/.ppm/.pgm/.bmp ...
- нужно простое и быстрое в работе приложение для таких целей.
Код: Выделить всё
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import threading
import numpy as np
import sys, os, time, argparse
from common import *
parser = argparse.ArgumentParser() # construct the argument parse and parse the arguments
parser.add_argument( '-i', '--image', required = False, help = 'video stream source' )
parser.add_argument( '-k', '--known', required = False, help = 'known persons directory' )
parser.add_argument( '-v', '--verbose', action = 'count', help = 'increase output verbosity' )
args = vars( parser.parse_args() )
debug = set_debug( args[ 'verbose' ] ) # verbose level
if debug > 1: print( args )
if debug: print( get_version() )
dir_name = './' # known faces directory
if args[ 'known' ] != None:
dir_name = args[ 'known' ]
if not os.path.isdir( dir_name ):
print( 'illegal directory: '.format( dir_name ) )
sys.exit( 1 )
root = tk.Tk() # main frame
root.geometry( '640x480+200+100' )
root.resizable( width = False, height = False )
root.title( 'Select images, ' + get_version() )
c1 = tk.Canvas( root )
lock = threading.Semaphore()
finish = False # quit flag
image = None
def runImage():
global lock, finish, image
sourcer = get_source( args[ 'image' ] ) # get images sourcer
first = True
try: # while exit...
while not finish:
lock.acquire()
ret, frame, delay = sourcer() # grab a single frame
lock.release()
if not ret: break # end of stream
if not isinstance( frame, np.ndarray ): # wrong format file
continue
if finish: break
if 2 == frame.ndim: # gray scale to BGR
frame = cv2.cvtColor( frame, cv2.COLOR_GRAY2BGR )
if first and debug > 0:
height = np.size( frame, 0 ); width = np.size( frame, 1 )
print( 'OpenCV: w={} , h={}'.format( width, height ) )
frame = cv2.cvtColor( frame, cv2.COLOR_BGR2RGB ) # convert from BGR to RGB
image = Image.fromarray( frame, 'RGB' ) # PIL image
if finish: break
if first and debug > 0:
height = image.height; width = image.width
print( 'PIL: w={} , h={}'.format( width, height ) )
tkimg = ImageTk.PhotoImage( image ) # Tk image
if finish: break
if first and debug > 0:
print( 'PhotoImage: w={} , h={}'.format( tkimg.width(), tkimg.height() ) )
c1.winfo_toplevel().geometry( '{}x{}+200+100'.format( tkimg.width(), tkimg.height() + 50 ) )
if finish: break
c1.create_image( tkimg.width() / 2, tkimg.height() / 2, image = tkimg )
c1.pack( side = 'top', fill = 'both', expand = True )
if finish: break
time.sleep( delay / 1000. )
first = False
except ( AttributeError, RuntimeError, KeyboardInterrupt, Exception ) as error:
lock.release()
if debug > 1: print( 'thread function exception' )
return
else:
if debug > 1: print( 'thread function break' )
return
def on_delete():
global dir_name
options = { # define options for deleting
'title' : 'Delete image file',
'filetypes' : [ ( "Image", ("*.jpg","*.png","*.gif" ) ),
( "Other", ("*.ppm","*.pgm","*.bmp" ) ),
( "All files", "*.*" ) ],
}
title = filedialog.askopenfilename( **options )
if 0 == len( title ): return # cancel
n = title.rfind( os.sep )
dir_name = title[ 0:n ]
os.remove( title )
b2 = tk.Button( root, text = 'Delete image' )
b2.pack( side = 'bottom' )
b2[ 'command' ] = on_delete # b2.bind( '<Button-1>', on_delete )
file_name = '.jpg'
def on_save():
global file_name, dir_name, lock
lock.acquire()
options = { # define options for saving
'title' : 'Save image as file...',
'filetypes' : [ ( "Image", ("*.jpg","*.png","*.gif" ) ),
( "Other", ("*.ppm","*.pgm","*.bmp" ) ),
( "All files", "*.*" ) ],
'initialfile' : file_name,
'initialdir' : dir_name
}
title = filedialog.asksaveasfilename( **options ) # select image file
if 0 == len( title ): # cancel
lock.release()
return
n = title.rfind( os.sep )
dir_name, file_name = title[ 0:n ], title[ n + 1: ]
if debug > 1: print( '{} => {} | {}'.format( title, dir_name, file_name ) )
try:
image.save( title )
except ( ValueError, Exception ) as error:
print( "error: image file can't save: {}!".format( error ) )
lock.release()
b1 = tk.Button( root, text = ' Save as... ' )
b1.pack( side = 'bottom' )
b1[ 'command' ] = on_save # b1.bind( '<Button-1>', on_save )
sys.setswitchinterval( 1 )
thread = threading.Thread( target = runImage )
thread.start() # visualisation video ...
def on_closing(): # exit application
global finish
print( ' ... waiting ...' )
lock.acquire()
t1 = time.strftime( '%H:%M:%S' )
finish = True
root.destroy()
thread.join( timeout = 3 )
t2 = time.strftime( '%H:%M:%S' )
if debug > 1:
print( '{} ... {} - thread is running: {}'.format( t1, t2, thread.is_alive() ) )
if( thread.is_alive() ):
raise KeyboardInterrupt( 'thread not finished: press ^C' )
lock.release()
sys.exit()
def on_closing1():
lock.acquire()
on_closing()
root.protocol( 'WM_DELETE_WINDOW', on_closing ) # winclose interrupt
root.bind( '<Escape>', lambda e: on_closing() ) # Esc interrupt
try:
root.mainloop()
except KeyboardInterrupt: # ^C interrupt
if debug > 1: print( '\n***************' )
on_closing()
Сложность и 1/3 кода свяязаны с тем, что нужно корректно остановить,
завершить приложение, и сделать это нужно асинхронно - одновременно с отображением видео в окно.
Код: Выделить всё
olej@ACER:~/2019_WORK/own.WORK/AplitSoft/FaceDL/fred$ ./fred.py -h
usage: fred.py [-h] [-i IMAGE] [-k KNOWN] [-v]
optional arguments:
-h, --help show this help message and exit
-i IMAGE, --image IMAGE
video stream source
-k KNOWN, --known KNOWN
known persons directory
-v, --verbose increase output verbosity
Из потока -i мы набиваем отдельными изображениями-файлами каталог -k.