Adding viewer capability for duplicate/similarity searches
This commit is contained in:
@@ -41,7 +41,10 @@ def setup_options():
|
|||||||
parser.add_argument("--small",action="store_true",dest="searchsmall",default=False,
|
parser.add_argument("--small",action="store_true",dest="searchsmall",default=False,
|
||||||
help="Return a list of small files, smaller than -m INT. This option will flip the 'Add new files' option. [%(default)s]")
|
help="Return a list of small files, smaller than -m INT. This option will flip the 'Add new files' option. [%(default)s]")
|
||||||
parser.add_argument("--similar",type=str,dest="similarity",default=None,
|
parser.add_argument("--similar",type=str,dest="similarity",default=None,
|
||||||
help="Search list for similar images. Value 0-255 for similarity threshold. 0=high similarity. If value is a filename, search similar to that image.")
|
help="Search list for similar images. Value 0-255 for similarity threshold. 0=high similarity. "+
|
||||||
|
"If value is a filename, search similar to that image.")
|
||||||
|
parser.add_argument("--viewer",type=str,dest="viewer",default=None,
|
||||||
|
help="Program to view images, %%f refers to filename(s)")
|
||||||
parser.add_argument("-x",action="append",dest="exclude",default=[],
|
parser.add_argument("-x",action="append",dest="exclude",default=[],
|
||||||
help="Exclude folder name from the lists. This option may be issued several times")
|
help="Exclude folder name from the lists. This option may be issued several times")
|
||||||
parser.add_argument('startpath', action="store",default='.', nargs='?')
|
parser.add_argument('startpath', action="store",default='.', nargs='?')
|
||||||
@@ -308,40 +311,65 @@ def get_fingerprint(filename):
|
|||||||
values+='0'
|
values+='0'
|
||||||
return str(int(values,2))
|
return str(int(values,2))
|
||||||
|
|
||||||
def find_fingerprint_similar(sqlfile,thr):
|
def find_fingerprint_similar(opts):
|
||||||
''' Find all similar images, nearest match more similar than thr '''
|
''' Find all similar images, nearest match more similar than thr '''
|
||||||
conn=sqlite3.connect(sqlfile)
|
|
||||||
|
thr=int(opts.similarity)
|
||||||
|
conn=sqlite3.connect(opts.sqlfile)
|
||||||
conn.text_factory=str
|
conn.text_factory=str
|
||||||
db1=conn.cursor()
|
db1=conn.cursor()
|
||||||
db2=conn.cursor()
|
db2=conn.cursor()
|
||||||
db1.execute("SELECT file,fingerprint,width,height FROM list ORDER BY file")
|
db1.execute("SELECT file,fingerprint,sharpness,width,height,R,G,B FROM list WHERE sharpness > 0 ORDER BY file")
|
||||||
hits=[]
|
hits=[]
|
||||||
|
hit_list=[]
|
||||||
for i,hit1 in enumerate(db1):
|
for i,hit1 in enumerate(db1):
|
||||||
if hit1[0] in hits:
|
if hit1[0] in hit_list:
|
||||||
continue
|
continue
|
||||||
this=[hit1[0],'',sys.maxint,int(hit1[1]),hit1[2]*hit1[3]]
|
cmp=hit1[0]
|
||||||
db2.execute("SELECT file,fingerprint,width,height FROM list ORDER BY file")
|
fp=int(hit1[1])
|
||||||
|
sp=hit1[2]
|
||||||
|
dims=hit1[3:5]
|
||||||
|
pixels=dims[0]*dims[1]
|
||||||
|
colors=hit1[5:8]
|
||||||
|
db2.execute("SELECT file,fingerprint,sharpness,width,height,R,G,B FROM list WHERE sharpness > 0 ORDER BY file")
|
||||||
|
this1=[ [cmp, 0,sp,int(hit1[3]),int(hit1[4]),0,pixels] ]
|
||||||
for hit2 in db2:
|
for hit2 in db2:
|
||||||
if hit2[0]==this[0]:
|
if hit2[0]==cmp:
|
||||||
continue
|
continue
|
||||||
similarity=bin(this[3]^int(hit2[1])).count('1')
|
similarity=bin(fp^int(hit2[1])).count('1')
|
||||||
if similarity<thr:
|
if similarity<thr:
|
||||||
if similarity<this[2]:
|
this2=[hit2[0], similarity, hit2[2],
|
||||||
this[2]=similarity
|
int(hit2[3]),int(hit2[4]),
|
||||||
this[1]=hit2[0]
|
abs( hit2[5] - colors[0] )+abs( hit2[6] - colors[1] )+abs( hit2[7] - colors[2] ),
|
||||||
if hit2[2]*hit2[3] < this[4]:
|
int(hit2[3])*int(hit2[4])]
|
||||||
foo=this[1]
|
this1.append(this2)
|
||||||
this[1]=this[0]
|
hit_list.append(hit2[0])
|
||||||
this[0]=foo
|
this1.sort(key=lambda x: x[1])
|
||||||
hits.append(hit2[0])
|
if len(this1)>1:
|
||||||
if this[2]<thr:
|
hits.append(this1)
|
||||||
print('"%s" "%s":%i' % ( this[0], this[1], this[2] ))
|
hit_list.append(cmp)
|
||||||
|
|
||||||
|
if i==0:
|
||||||
|
print("No measurements found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
for src in hits:
|
||||||
|
file_len=str(max([len(x[0]) for x in src]))
|
||||||
|
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: ^5}x{: ^5}').format("File","Diff","CDel","Shrp","Wth","Hgt"))
|
||||||
|
for c in range(len(src)):
|
||||||
|
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: >5}x{: >5}').format(src[c][0],src[c][1],"%.2f"%src[c][5],
|
||||||
|
"%.1f" % src[c][2],src[c][3],src[c][4]))
|
||||||
|
if opts.viewer:
|
||||||
|
fnames=[x[0] for x in src]
|
||||||
|
subprocess.call(opts.viewer.replace('%f', " ".join(fnames)), shell=True)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def find_fingerprint_nearest(sqlfile,cmp):
|
def find_fingerprint_nearest(opts):
|
||||||
''' Find nearest match '''
|
''' Find nearest match to given file '''
|
||||||
cmp=os.path.abspath(cmp)
|
|
||||||
conn=sqlite3.connect(sqlfile)
|
cmp=os.path.abspath(opts.similarity)
|
||||||
|
conn=sqlite3.connect(opts.sqlfile)
|
||||||
conn.text_factory=str
|
conn.text_factory=str
|
||||||
db1=conn.cursor()
|
db1=conn.cursor()
|
||||||
if is_listed(db1, cmp):
|
if is_listed(db1, cmp):
|
||||||
@@ -377,6 +405,10 @@ def find_fingerprint_nearest(sqlfile,cmp):
|
|||||||
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: ^5}x{: ^5}').format("File","Diff","CDel","Shrp","Wth","Hgt"))
|
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: ^5}x{: ^5}').format("File","Diff","CDel","Shrp","Wth","Hgt"))
|
||||||
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: >5}x{: >5}').format(cmp,"","","%.1f" % sp,dims[0],dims[1]))
|
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: >5}x{: >5}').format(cmp,"","","%.1f" % sp,dims[0],dims[1]))
|
||||||
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: >5}x{: >5}').format(this[0], this[1],"%.2f"%this[5], "%.1f" % this[2],this[3], this[4]))
|
print( ('{: <'+file_len+'} {: >4} {: >4} {: >4} {: >5}x{: >5}').format(this[0], this[1],"%.2f"%this[5], "%.1f" % this[2],this[3], this[4]))
|
||||||
|
|
||||||
|
if opts.viewer:
|
||||||
|
subprocess.call(opts.viewer.replace('%f', " ".join((cmp,this[0]))), stderr=subprocess.STDOUT, shell=True)
|
||||||
|
|
||||||
|
|
||||||
def append_sharpness(sqlfile):
|
def append_sharpness(sqlfile):
|
||||||
conn=sqlite3.connect(sqlfile)
|
conn=sqlite3.connect(sqlfile)
|
||||||
@@ -511,7 +543,7 @@ def print_structure(files):
|
|||||||
i+=1
|
i+=1
|
||||||
return
|
return
|
||||||
|
|
||||||
def print_dup_structure(files):
|
def print_dup_structure(files,opts):
|
||||||
i=1
|
i=1
|
||||||
for hash in files:
|
for hash in files:
|
||||||
#print(hash[0])
|
#print(hash[0])
|
||||||
@@ -519,6 +551,9 @@ def print_dup_structure(files):
|
|||||||
for f in hash[1]:
|
for f in hash[1]:
|
||||||
fnames.append(' "'+f[0]+'"')
|
fnames.append(' "'+f[0]+'"')
|
||||||
print "%(i)d:%(n)d:%(f)s " % {'i':i, 'n':len(fnames), 'f':",".join(fnames)}
|
print "%(i)d:%(n)d:%(f)s " % {'i':i, 'n':len(fnames), 'f':",".join(fnames)}
|
||||||
|
if opts.viewer:
|
||||||
|
fnames=[x[0] for x in hash[1]]
|
||||||
|
subprocess.call(opts.viewer.replace('%f', " ".join(fnames)), shell=True)
|
||||||
i+=1
|
i+=1
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -548,12 +583,12 @@ def main():
|
|||||||
find_color_nearest(options.sqlfile,options.nearestcolor)
|
find_color_nearest(options.sqlfile,options.nearestcolor)
|
||||||
if options.similarity!=None:
|
if options.similarity!=None:
|
||||||
if os.path.exists(options.similarity):
|
if os.path.exists(options.similarity):
|
||||||
find_fingerprint_nearest(options.sqlfile,options.similarity)
|
find_fingerprint_nearest(options)
|
||||||
else:
|
else:
|
||||||
find_fingerprint_similar(options.sqlfile,int(options.similarity))
|
find_fingerprint_similar(options)
|
||||||
if options.duplicate:
|
if options.duplicate:
|
||||||
files=find_duplicates(options.sqlfile,options.startpath)
|
files=find_duplicates(options.sqlfile,options.startpath)
|
||||||
print_dup_structure(files)
|
print_dup_structure(files,options)
|
||||||
if options.searchsmall:
|
if options.searchsmall:
|
||||||
files=find_smalls(options.minsize,options.sqlfile)
|
files=find_smalls(options.minsize,options.sqlfile)
|
||||||
if options.deleteFiles:
|
if options.deleteFiles:
|
||||||
|
|||||||
Reference in New Issue
Block a user