def diff(im1_file,
im2_file,
delete_diff_file=False,
diff_img_file=diff_img_file):
im1 = Image.open(im1_file)
im2 = Image.open(im2_file)
diff_img = ImageChops.difference(im1,im2)
diff_img.convert('RGB').save(diff_img_file)
stat = ImageStat.Stat(diff_img)
# can be [r,g,b] or [r,g,b,a]
sum_channel_values = sum(stat.mean)
max_all_channels = len(stat.mean) * 100
diff_ratio = sum_channel_values/max_all_channels
if delete_diff_file:
remove(diff_img_file)
return diff_ratio
python类difference()的实例源码
def get_args():
parser = argparse.ArgumentParser(
description='Generate a diff image from two images \
and/or find difference percentage')
parser.add_argument('image1',
type=str,
help='first image')
parser.add_argument('image2',
type=str,
help='second image')
parser.add_argument('--ratio', '-r',
dest='use_ratio',
action='store_true',
help='return a ratio instead of percentage')
parser.add_argument('--delete', '-d',
dest='delete_diff_file',
action='store_true',
help='delete diff image file')
parser.add_argument('--filename', '-f',
dest='diff_img_file',
type=str,
default=diff_img_file,
help='filename with valid extension to store diff image \
(defaults to diff_img.jpg)')
return parser.parse_args()
def redraw_required(self, image):
"""
Calculates the difference from the previous image, return a boolean
indicating whether a redraw is required. A side effect is that
``bounding_box`` and ``image`` attributes are updated accordingly, as is
priming :py:func:`getdata`.
:param image: An image to render
:type image: PIL.Image.Image
:returns: ``True`` or ``False``
"""
self.bounding_box = ImageChops.difference(self.image, image).getbbox()
if self.bounding_box is not None:
self.image = image.copy()
return True
else:
return False
def capture_cropped_screenshot(self, output_file, background='White'):
"""Takes a screenshot of the current page, and writes it to `output_file`. The image is cropped
to contain only the parts containing something other than the background color.
:param output_file: The name of the file to which to write the screenshot.
:keyword background: The color to use as background color when cropping.
"""
self.web_driver.get_screenshot_as_file(output_file)
try:
from PIL import Image, ImageChops
im = Image.open(output_file)
bg = Image.new(im.mode, im.size, background)
diff = ImageChops.difference(im, bg)
bbox = diff.getbbox()
cropped = im.crop(bbox)
cropped.save(output_file)
except ImportError:
logging.warning('PILlow is not available, unable to crop screenshots')
def _compare_entropy(start_slice, end_slice, slice, difference):
"""
Calculate the entropy of two slices (from the start and end of an axis),
returning a tuple containing the amount that should be added to the start
and removed from the end of the axis.
"""
start_entropy = utils.image_entropy(start_slice)
end_entropy = utils.image_entropy(end_slice)
if end_entropy and abs(start_entropy / end_entropy - 1) < 0.01:
# Less than 1% difference, remove from both sides.
if difference >= slice * 2:
return slice, slice
half_slice = slice // 2
return half_slice, slice - half_slice
if start_entropy > end_entropy:
return 0, slice
else:
return slice, 0
def rmsdiff(im1, im2):
im1 = im1.convert("RGBA")
im2 = im2.convert("RGBA")
diff = ImageChops.difference(im1, im2)
h = diff.histogram()
blah = np.array(h, dtype=int)
okay = (np.arange(1024)%256)**2
rms = sqrt(np.sum(blah*okay)/float(im1.size[0] * im1.size[1]))
# sq = [value*((idx%256)**2) for idx, value in enumerate(h)]
# sum_of_squares = sum(sq)
# rms = sqrt(sum_of_squares/float(im1.size[0] * im1.size[1]))
return rms
def get_fitness(self, target):
"""
Get fitness of the individual.
This was calculated by RMS distance of histograms.
Args:
target: target image.
Returns:
the fitness value.
"""
h = ImageChops.difference(target, self.im).histogram()
return math.sqrt(reduce(operator.add,
map(lambda h, i: h*(i**2),
h, range(256)*3)) /
(float(target.size[0]) * target.size[1]))
def create_character(fontpath, size, c, bypp, crop, bpp):
try:
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from PIL import ImageChops
except:
# we will get respawn hopefully after python-PIL is loaded
print 'failed to load PIL to create fonts, aborting...'
import time
time.sleep(3)
exit(1)
ifont = ImageFont.truetype(fontpath, size)
size = ifont.getsize(c)
image = Image.new('RGBA', size)
draw = ImageDraw.Draw(image)
draw.text((0, 0), c, font=ifont)
if crop:
bg = Image.new(image.mode, image.size, image.getpixel((0, 0)))
diff = ImageChops.difference(image, bg)
bbox = diff.getbbox()
if bbox:
image = image.crop(bbox)
if bpp:
data = list(image.getdata())
for i in range(len(data)):
d = 255 / (1<<bpp)
v = int(round(data[i][0] / (255 / (1<<bpp))) * (255 / ((1<<bpp)-1)))
data[i] = (v,v,v,v)
image.putdata(data)
return ugfx.surface(image.size[0], image.size[1], bypp, image.tobytes())
def do_difference(self):
"""usage: difference <image:pic1> <image:pic2>
Pop the two top images, push the difference image
"""
from PIL import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
self.push(ImageChops.difference(image1, image2))
def do_subtract(self):
"""usage: subtract <image:pic1> <image:pic2> <int:offset> <float:scale>
Pop the two top images, produce the scaled difference with offset.
"""
from PIL import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
scale = float(self.do_pop())
offset = int(self.do_pop())
self.push(ImageChops.subtract(image1, image2, scale, offset))
# ImageEnhance classes
def differnce_images(path_one, path_two, diff_save_location):
image_one = Image.open(path_one)
image_two = Image.open(path_two)
#Difference calculated here
diff = ImageChops.difference(image_one, image_two)
#Method to check if there is no difference
if diff.getbbox() is None:
print "No difference in the images"
return
else:
print diff.getbbox()
diff.save(diff_save_location)
def equal(self, img1, img2, skip_area=None):
"""Compares two screenshots using Root-Mean-Square Difference (RMS).
@param img1: screenshot to compare.
@param img2: screenshot to compare.
@return: equal status.
"""
if not HAVE_PIL:
return None
# Trick to avoid getting a lot of screen shots only because the time in the windows
# clock is changed.
# We draw a black rectangle on the coordinates where the clock is locates, and then
# run the comparison.
# NOTE: the coordinates are changing with VM screen resolution.
if skip_area:
# Copying objects to draw in another object.
img1 = img1.copy()
img2 = img2.copy()
# Draw a rectangle to cover windows clock.
for img in (img1, img2):
self._draw_rectangle(img, skip_area)
# To get a measure of how similar two images are, we use
# root-mean-square (RMS). If the images are exactly identical,
# this value is zero.
diff = ImageChops.difference(img1, img2)
h = diff.histogram()
sq = (value * ((idx % 256)**2) for idx, value in enumerate(h))
sum_of_squares = sum(sq)
rms = math.sqrt(sum_of_squares/float(img1.size[0] * img1.size[1]))
# Might need to tweak the threshold.
return rms < 8
def assert_identical_image(reference, target):
bbox = ImageChops.difference(reference, target).getbbox()
assert bbox is None
def _crop_with_bbox(image):
bg = Image.new(image.mode, image.size, image.getpixel((0,0)))
diff = ImageChops.difference(image,bg)
bbox = diff.getbbox()
return image.crop(bbox)
def checkSimilarPictures(pic1, pic2, x_max=DIFF_THRESHOLD, y_max=DIFF_THRESHOLD):
# print pic1, pic2
image1 = Image.open(pic1).convert('L')
image2 = Image.open(pic2).convert('L')
diff = ImageChops.difference(image1, image2)
box = diff.getbbox()
if box is None:
return True, False
xdiff = abs(box[0] - box[2])
ydiff = abs(box[1] - box[3])
if(xdiff >= x_max and ydiff >= y_max):
# print 'Box', xdiff, ydiff
h = diff.histogram()
sq = (v*(i**2) for i, v in enumerate(h))
sum_of_squares = sum(sq)
rms = math.sqrt(sum_of_squares/float(image1.size[0] * image1.size[1]))
# print rms
if rms > RMS_THRESHOLD:
# print 'RMS', rms
if(xdiff >= CRASH_THRESHOLD and ydiff >= CRASH_THRESHOLD):
return False, True
return False, False
return True, False
def autocrop(im, autocrop=False, **kwargs):
"""
Remove any unnecessary whitespace from the edges of the source image.
This processor should be listed before :func:`scale_and_crop` so the
whitespace is removed from the source image before it is resized.
autocrop
Activates the autocrop method for this image.
"""
if autocrop:
# If transparent, flatten.
if utils.is_transparent(im) and False:
no_alpha = Image.new('L', im.size, (255))
no_alpha.paste(im, mask=im.split()[-1])
else:
no_alpha = im.convert('L')
# Convert to black and white image.
bw = no_alpha.convert('L')
# bw = bw.filter(ImageFilter.MedianFilter)
# White background.
bg = Image.new('L', im.size, 255)
bbox = ImageChops.difference(bw, bg).getbbox()
if bbox:
im = im.crop(bbox)
return im
def assertImagesEqual(self, im1, im2, msg=None):
if im1.size != im2.size or (
ImageChops.difference(im1, im2).getbbox() is not None):
raise self.failureException(
msg or 'The two images were not identical')
def near_identical(im1, im2):
"""
Check if two images are identical (or near enough).
"""
diff = ImageChops.difference(im1, im2).histogram()
for color in diff[2:]:
if color:
return False
return True
def equal(self, img1, img2, skip_area=None):
"""Compares two screenshots using Root-Mean-Square Difference (RMS).
@param img1: screenshot to compare.
@param img2: screenshot to compare.
@return: equal status.
"""
if not HAVE_PIL:
return None
# Trick to avoid getting a lot of screen shots only because the time in the windows
# clock is changed.
# We draw a black rectangle on the coordinates where the clock is locates, and then
# run the comparison.
# NOTE: the coordinates are changing with VM screen resolution.
if skip_area:
# Copying objects to draw in another object.
img1 = img1.copy()
img2 = img2.copy()
# Draw a rectangle to cover windows clock.
for img in (img1, img2):
self._draw_rectangle(img, skip_area)
# To get a measure of how similar two images are, we use
# root-mean-square (RMS). If the images are exactly identical,
# this value is zero.
diff = ImageChops.difference(img1, img2)
h = diff.histogram()
sq = (value * ((idx % 256)**2) for idx, value in enumerate(h))
sum_of_squares = sum(sq)
rms = math.sqrt(sum_of_squares/float(img1.size[0] * img1.size[1]))
# Might need to tweak the threshold.
return rms < 8
def trim(im):
bg = Image.new(im.mode, im.size, im.getpixel((0, 0)))
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
def trim(im):
bg = Image.new(im.mode, im.size, im.getpixel((0, 0)))
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
else:
return im
def trim_whitespace(im):
bg = Image.new(im.mode, im.size, im.getpixel((0, 0)))
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
def get_fitness(self, other_image):
if not self.cached_fitness:
im = self.get_image()
new_im = ImageChops.difference(im, other_image)
st = ImageStat.Stat(new_im)
# Add in a penalty for number of triangles used
additional_triangle_weight = len(self.triangles) * TRIANGLE_WEIGHT
self.cached_fitness = sum(st.sum[:3]) + additional_triangle_weight
return self.cached_fitness
####################################################################
def trim(self, im):
"""
Auto-trim
"""
bg = Image.new(im.mode, im.size, im.getpixel((0, 0)))
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
def trim(im):
pixel = (255, 255, 255) # ????????????? ?? ????? ????
# pixel = im.getpixel((0,0)) # ????????????? ?? ??????? ? ?????? ???????? ????
bg = Image.new(im.mode, im.size, pixel)
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
bbox = diff.getbbox()
logger.info(bbox)
if bbox:
return im.crop(bbox)
else:
return im
def is_greyscale(im):
"""
Check if image is monochrome (1 channel or 3 identical channels)
"""
if im.mode not in ("L", "RGB"):
raise ValueError("Unsuported image mode")
if im.mode == "RGB":
rgb = im.split()
if ImageChops.difference(rgb[0],rgb[1]).getextrema()[1]!=0:
return False
if ImageChops.difference(rgb[0],rgb[2]).getextrema()[1]!=0:
return False
return True
def test_extracticon():
filepath = 'tests/data/hello.exe'
extractor = ExtractIcon(filepath)
groups = extractor.get_group_icons()
assert 1 == len(groups)
assert 9 == len(groups[0])
assert 6 == extractor.best_icon(groups[0])
im1 = extractor.export(groups[0], 6)
im2 = Image.open('tests/data/psxfin.png')
b = ImageChops.difference(im1, im2).getbbox()
assert b is None
def _compare_images(self, im1, im2):
"""Compares two images for similarity.
Args:
im1 (``PIL.Image.Image``): an image to be compared
im2 (``PIL.Image.Image``): an image to be compared
Returns:
bool: ``False`` if similar and ``True`` if not.
"""
diff = ImageChops.difference(im1, im2)
bbox = diff.getbbox()
if not bbox:
return False
else:
histogram = diff.histogram()
squares = (value * ((idx % 256) ** 2) for idx, value in enumerate(histogram))
sum_of_squares = sum(squares)
rms = math.sqrt(sum_of_squares/float(im1.size[0] * im1.size[1]))
if rms <= self.options['threshold']:
return False
else:
return True
def equal(im1, im2):
"""Returns True if two images are equal"""
return ImageChops.difference(im1, im2).getbbox() is None
def download_single_checked(self, url: str, destination: str, prefix: str):
"""
Download a single image, checking for failure cases.
:param url: Url to attempt to download an image from
:param destination: folder to store downloaded image in
:param prefix: synset id or descriptor word for url
:return: Filename or None as success if downloaded succeeded
"""
# splits to (`url+filename`, `.`, `filesuffix`)
filetype = url.strip().rpartition('.')[2]
keep = None
# We need a naming scheme that won't overwrite anything
# Option a) pass in the index with the url
# Option b) use a sufficiently sized random number
# > Only after generating 1 billion UUIDs every second for the next 100 years,
# > the prob of creating just one duplicate would be about 50%.
# > The prob of one duplicate would be about 50% if every person on earth owns 600 million UUIDs.
file = os.path.join(destination, '{}-{}.{}'.format(prefix, uuid.uuid4(), filetype))
try:
# require either .png, .jpg, or .jpeg
if filetype in ['png', 'jpg', 'jpeg']:
# Get the file
response = requests.get(url, stream=True, timeout=5)
if response.status_code == 200:
with open(file, 'wb') as out_file:
response.raw.decode_content = True
shutil.copyfileobj(response.raw, out_file)
keep = False # None -> False :: We have a file now, need to verify
# Check we got an image not some HTML junk 404
with Image.open(file) as img:
# Logic here is that if we can interpret the image then its good
# PIL is lazy - the raster data isn't loaded until needed or `load` is called explicitly'
keep = True # False -> True :: We've decided to keep the download
# Look through the known 'not available images'
for bin_image in binary_images.values():
# If this image size matches
if img.size == bin_image['size']:
# Compare the raster data
with Image.open(io.BytesIO(bin_image['raster'])) as raster:
if ImageChops.difference(raster, img).getbbox() is None:
# No bounding box for the difference of these images, so
# this is a 'image not availble' image
keep = False # True -> False :: Changed our mind..
# If anything above failed we're not keeping this one
except:
keep = False
finally:
if keep is None or keep is False:
if os.path.isfile(file):
os.remove(file)
else:
return file # Return the name of the downloaded file, otherwise implicit return None