1. Split image into 5x5 pixel image blocks
2. Calculate information entropy of these blocks (actually sum of entropy in 3 color channels)
3. Find similar entropy blocks.
4. [...] filter out small groups of blocks (seems like noise, huh ? ). Blah, blah...
5. Picture these similar entropy blocks on top of original image as red color layer.
Now real part (as you know already) - Python code which does the job [you need PIL module to run this]:
from PIL import Image
from math import *
def entropysum(pixels):
"""
Calculating information entropy for image
region and returning entropy sum for
all 3 color channels
"""
cr = [r for (r,g,b) in pixels]
cg = [g for (r,g,b) in pixels]
cb = [b for (r,g,b) in pixels]
er = 0.0
eg = 0.0
eb = 0.0
for r in set(cr):
p = float(cr.count(r))/len(cr)
if p > 0.0: er += -p * log(p,2)
for g in set(cg):
p = float(cg.count(g))/len(cg)
if p > 0.0: eg += -p * log(p,2)
for b in set(cb):
p = float(cb.count(b))/len(cb)
if p > 0.0: eb += -p * log(p,2)
return er + eg + eb
def decompose(image, block_len):
"""
Decomposing given image into some number of
smaller images of size block_len*block_len
"""
parts = []
w, h = image.size
for x in range(0, w, block_len):
for y in range(0, h, block_len):
locim = image.crop((x,y,x+block_len,y+block_len))
acc = entropysum(list(locim.getdata()))
parts.append((acc,x,y,locim))
parts.sort()
return parts
def similarparts(imagparts):
"""
Detecting similar image blocks by comparing
entropy of given images. Two images considered
being equal if entropy difference is not big.
"""
dupl = []
for i in range(len(imagparts)-1):
acc1, x1, y1, im1 = imagparts[i]
acc2, x2, y2, im2 = imagparts[i+1]
if acc1 == acc2 == 0:
gain = 0.0
else:
gain = 100.0 * (1.0 - acc1 / acc2)
if 0.01 < gain < 0.1 :
if imagparts[i] not in dupl:
dupl.append(imagparts[i])
if imagparts[i+1] not in dupl:
dupl.append(imagparts[i+1])
return dupl
def clusterparts(parts):
"""
Grouping nearest images into groups.
This is done, because we need to
filter out very small groups. We
want to know only big differences.
"""
filtparts = []
clust = {}
belongs = {}
w,h = parts[0][3].size
# assign all parts to clusters
for i in range(len(parts)):
acc, x, y, im = parts[i]
sides = []
sides.append(str(x)+str(y)+str(x+w)+str(y))
sides.append(str(x+w)+str(y)+str(x+w)+str(y+h))
sides.append(str(x)+str(y+h)+str(x+w)+str(y+h))
sides.append(str(x)+str(y)+str(x)+str(y+h))
# detect side already in cluster
fc = None
for s in sides:
if belongs.has_key(s):
fc = belongs[s]
break
# if this is new cluster
if fc == None:
fc = len(clust) + 1
clust[fc] = 1
else:
clust[fc] += 1
# set cluster for rectangle sides
for s in sides:
if not belongs.has_key(s):
belongs[s] = fc
# filter out small clusters
for i in range(len(parts)):
acc, x, y, im = parts[i]
side = str(x)+str(y)+str(x+w)+str(y)
cl = belongs[side]
if clust[cl] > 2:
filtparts.append(parts[i])
return filtparts
def marksimilar(image, dparts):
"""
Mark found similar image blocks on
original image, by applying red layer
on similar parts of image.
"""
if dparts:
colormask = Image.new('RGB', dparts[0][3].size,(255,0,0))
for (acc,x,y,im) in dparts:
im = Image.blend(im, colormask, 0.4)
image.paste(im,(x,y))
return image
if __name__ == '__main__':
im = Image.open("1.jpg")
ls = decompose(im, 5)
dparts = similarparts(ls)
cparts = clusterparts(dparts)
im = marksimilar(im, cparts)
im.show()
So these are the results after running this script on several images:
Conclusion
So this algorithm is an interesting tool for exploration of information entropy in image. Maybe in some cases it could be a tool for analyzing very similar texture zones. BTW information entropy may be used for hashing image. Hashing image is useful, because it lets us to search similar images in database (for example) by its hash.
Have fun !
No comments:
Post a Comment
Comment will be posted after comment moderation.
Thank you for your appreciation.