Skip to content

Instantly share code, notes, and snippets.

@diramazioni
Last active April 11, 2023 20:46
Show Gist options
  • Save diramazioni/bb45705e00006e594e7fa5165377feb1 to your computer and use it in GitHub Desktop.
Save diramazioni/bb45705e00006e594e7fa5165377feb1 to your computer and use it in GitHub Desktop.
Find out the "bluriness" of each extracted image-frame to select the best image out of N frames, copy the resulting frames in a new dir mantaining exif info
#!/usr/bin/env python
"""
### Find out the "bluriness" of each extracted image-frame to select the best image out of N frames,
### copy the resulting frames in a new dir mantaining exif info
### Arguments: image_directory best_of_n_frames method (1 or 2)
### python blurCV_detect.py /home/SfM/footage 30 1
"""
import sys, glob, os, shutil
# sys.argv[1] image directory to operate
best_every = int(sys.argv[2]) # choose the best image every X frames
method = int(sys.argv[3]) # choose the method to compute the "bluriness" (1 or 2 value)
ok = 'ok_' + sys.argv[3] # dir name for selected images
from PIL import Image
import numpy
import cv2
import piexif
from collections import OrderedDict
import math
def median(values):
half = len(values) // 2
svalues = sorted(values)
if not len(svalues) % 2:
return (svalues[half - 1] + svalues[half]) / 2.0
return svalues[half]
def mean(values):
return sum(values)/len(values)
def stanDevPop(values):
length = len(values)
total_sum = 0
for i in range(length):
total_sum += (values[i]-mean(values))**2
return math.sqrt(total_sum/length)
def computeBlurSimple(filePath):
img = cv2.imread(filePath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
return numpy.max(cv2.convertScaleAbs(cv2.Laplacian(gray,3)))
def computeBlur(filePath):
thresh = 35
MinZero = 0.02
im=Image.open(filePath).convert('F')
x=numpy.asarray(im)
x_cropped=x[0:(numpy.shape(x)[0]/16)*16 - 1,0:(numpy.shape(x)[1]/16)*16 - 1]
LL1,(LH1,HL1,HH1)=pywt.dwt2(x_cropped,'haar')
LL2,(LH2,HL2,HH2)=pywt.dwt2(LL1 ,'haar')
LL3,(LH3,HL3,HH3)=pywt.dwt2(LL2 ,'haar')
Emap1=numpy.square(LH1) + numpy.square(HL1) + numpy.square(HH1)
Emap2=numpy.square(LH2) + numpy.square(HL2) + numpy.square(HH2)
Emap3=numpy.square(LH3) + numpy.square(HL3) + numpy.square(HH3)
dimx=numpy.shape(Emap1)[0]/8
dimy=numpy.shape(Emap1)[1]/8
Emax1=[]
vert=1
for j in range(0,dimx - 2):
horz=1;
Emax1.append([])
for k in range(0,dimy - 2):
Emax1[j].append(numpy.max(numpy.max(Emap1[vert:vert+7,horz:horz+7])))
horz=horz+8
vert=vert+8
dimx=numpy.shape(Emap2)[0]/4
dimy=numpy.shape(Emap2)[1]/4
Emax2=[]
vert=1
for j in range(0,dimx - 2):
horz=1;
Emax2.append([])
for k in range(0,dimy - 2):
Emax2[j].append(numpy.max(numpy.max(Emap2[vert:vert+3,horz:horz+3])))
horz=horz+4
vert=vert+4
dimx=numpy.shape(Emap3)[0]/2
dimy=numpy.shape(Emap3)[1]/2
Emax3=[]
vert=1
for j in range(0,dimx - 2):
horz=1;
Emax3.append([])
for k in range(0,dimy - 2):
Emax3[j].append(numpy.max(numpy.max(Emap3[vert:vert+1,horz:horz+1])))
horz=horz+2
vert=vert+2
N_edge=0
N_da=0
N_rg=0
N_brg=0
EdgeMap = []
for j in range(0, dimx - 2):
EdgeMap.append([])
for k in range(0, dimy - 2):
if (Emax1[j][k]>thresh) or (Emax2[j][k]>thresh) or (Emax3[j][k]>thresh):
EdgeMap[j].append(1)
N_edge = N_edge + 1
rg = 0
if (Emax1[j][k]>Emax2[j][k]) and (Emax2[j][k]>Emax3[j][k]):
N_da=N_da+1
elif (Emax1[j][k]<Emax2[j][k]) and (Emax2[j][k]<Emax3[j][k]):
rg = 1
N_rg=N_rg+1
elif (Emax2[j][k]>Emax1[j][k]) and (Emax2[j][k]>Emax3[j][k]):
rg = 1
N_rg=N_rg+1
if rg and (Emax1[j][k]<thresh):
N_brg=N_brg+1
else:
EdgeMap[j].append(0)
return float(N_da)/N_edge
def computeCanny(filePath):
img = cv2.imread(filePath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgCanny = cv2.Canny(gray, 225, 175)
nCountCanny = cv2.countNonZero(imgCanny)
dSharpness = nCountCanny * 1000.0 / (imgCanny.shape[0] * imgCanny.shape[1])
return dSharpness
def write_exif(filePath):
im = Image.open(filePath)
#exif_dict = piexif.load(im.info["exif"])
exif_dict = piexif.load(filePath)
if piexif.ImageIFD.XResolution not in exif_dict["0th"]:
print("adding exif %s" % filePath)
w, h = im.size
exif_dict["0th"][piexif.ImageIFD.XResolution] = (w, 1)
exif_dict["0th"][piexif.ImageIFD.YResolution] = (h, 1)
exif_bytes = piexif.dump(exif_dict)
im.save(filePath, "jpeg", exif=exif_bytes)
def chunks(odict, n):
"""Yield successive n-sized chunks from odict."""
for i in range(0, len(odict), n):
yield list(odict.keys())[i:i + n]
os.chdir(sys.argv[1])
if not os.path.exists(ok):
os.mkdir(ok)
oresult = OrderedDict()
values = []
for f in sorted(glob.glob('*.jpg')):
if method == 1:
val = computeCanny(f)
else:
val = computeBlur(f)
values.append(val)
oresult[f] = val
print(f, val)
#oresult = OrderedDict(result.items())
stdev = stanDevPop(values)
mean = mean(values)
median = median(values)
print('mean:', mean)
print('median:', median)
print('stdev:', stdev)
for ckeys in list(chunks(oresult, best_every)):
print('----')
chunkd = {key: oresult[key] for key in ckeys}
f, maximum = max(chunkd.items(), key=lambda k: k[1])
write_exif(f)
print(f, maximum)
shutil.copyfile(f, '%s/%s'% (ok,f))
''' This is an implementation of a post found here http://stackoverflow.com/a/20198278/1911518 '''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment