<reponame>jiayunhan/deep-anpr<filename>detect_attack.py
#!/usr/bin/env python
#
# Copyright (c) 2016 <NAME>
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
#     The above copyright notice and this permission notice shall be included
#     in all copies or substantial portions of the Software.
# 
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
#     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
#     NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
#     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
#     OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
#     USE OR OTHER DEALINGS IN THE SOFTWARE.


"""
Routines to detect number plates.

Use `detect` to detect all bounding boxes, and use `post_process` on the output
of `detect` to filter using non-maximum suppression.

"""


__all__ = (
	'detect',
	'post_process',
)


import collections
import itertools
import math
import sys

import cv2
import numpy
import tensorflow as tf

import common
import model

from detect_get_logits import get_attack_logits 

def make_scaled_ims(im, min_shape):
	ratio = 1. / 2 ** 0.5
	shape = (im.shape[0] / ratio, im.shape[1] / ratio)
	while True:
		shape = (int(shape[0] * ratio), int(shape[1] * ratio))
		if shape[0] < min_shape[0] or shape[1] < min_shape[1]:
			break
		yield cv2.resize(im, (shape[1], shape[0]))


def detect(im, param_vals):
    """
    Detect number plates in an image.

    :param im:
        Image to detect number plates in.

    :param param_vals:
        Model parameters to use. These are the parameters output by the `train`
        module.

    :returns:
        Iterable of `bbox_tl, bbox_br, letter_probs`, defining the bounding box
        top-left and bottom-right corners respectively, and a 7,36 matrix
        giving the probability distributions of each letter.

    """

    # Convert the image to various scales.
    scaled_ims = list(make_scaled_ims(im, model.WINDOW_SHAPE))
    #scaled_ims = hide_attack(im, param_vals)
    #print(scaled_ims[0].shape)

    # Load the model which detects number plates over a sliding window.
    x, y, params = model.get_detect_model()

    # Execute the model at each scale.
    with tf.Session(config=tf.ConfigProto()) as sess:
        y_vals = []
        for scaled_im in scaled_ims:
            feed_dict = {x: numpy.stack([scaled_im])}
            feed_dict.update(dict(zip(params, param_vals)))
            y_vals.append(sess.run(y, feed_dict=feed_dict))

    print(y_vals[0].shape)
    # Interpret the results in terms of bounding boxes in the input image.
    # Do this by identifying windows (at all scales) where the model predicts a
    # number plate has a greater than 50% probability of appearing.
    #
    # To obtain pixel coordinates, the window coordinates are scaled according
    # to the stride size, and pixel coordinates.
    count = 0
    for i, (scaled_im, y_val) in enumerate(zip(scaled_ims, y_vals)):
        for window_coords in numpy.argwhere(y_val[0, :, :, 0] >
                                                       -math.log(1./0.99 - 1)):

            count = count + 1
            letter_probs = (y_val[0,
                                  window_coords[0],
                                  window_coords[1], 1:].reshape(
                                    7, len(common.CHARS)))
            letter_probs = common.softmax(letter_probs)

            img_scale = float(im.shape[0]) / scaled_im.shape[0]

            bbox_tl = window_coords * (8, 4) * img_scale
            bbox_size = numpy.array(model.WINDOW_SHAPE) * img_scale

            present_prob = common.sigmoid(
                               y_val[0, window_coords[0], window_coords[1], 0])

            yield bbox_tl, bbox_tl + bbox_size, present_prob, letter_probs

    #print("Detected count: ", count) 

def detect_max_shape(im, param_vals):
    scaled_ims = list(make_scaled_ims(im, model.WINDOW_SHAPE))

    x, y, params = model.get_detect_model()

    # Execute the model at each scale.
    with tf.Session(config=tf.ConfigProto()) as sess:
        y_vals = []
        for scaled_im in scaled_ims:
            feed_dict = {x: numpy.stack([scaled_im])}
            feed_dict.update(dict(zip(params, param_vals)))
            y_vals.append(sess.run(y, feed_dict=feed_dict))

    # Interpret the results in terms of bounding boxes in the input image.
    # Do this by identifying windows (at all scales) where the model predicts a
    # number plate has a greater than 50% probability of appearing.
    #
    # To obtain pixel coordinates, the window coordinates are scaled according
    # to the stride size, and pixel coordinates.
    max_im = scaled_ims[0]
    max_prob = 0
    for i, (scaled_im, y_val) in enumerate(zip(scaled_ims, y_vals)):
        for window_coords in numpy.argwhere(y_val[0, :, :, 0] >
                                                       -math.log(1./0.99 - 1)):
            letter_probs = (y_val[0,
                                  window_coords[0],
                                  window_coords[1], 1:].reshape(
                                    7, len(common.CHARS)))
            letter_probs = common.softmax(letter_probs)

            img_scale = float(im.shape[0]) / scaled_im.shape[0]

            bbox_tl = window_coords * (8, 4) * img_scale
            bbox_size = numpy.array(model.WINDOW_SHAPE) * img_scale

            present_prob = common.sigmoid(
                               y_val[0, window_coords[0], window_coords[1], 0])

            if(present_prob > max_prob):
            	max_prob = present_prob
            	max_im = scaled_im 
    
    return max_im.shape

def isDetected(im, param_vals):
	im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) / 255.
	scaled_ims = list(make_scaled_ims(im_gray, model.WINDOW_SHAPE))
	x, y, params = model.get_detect_model()

	with tf.Session(config=tf.ConfigProto()) as sess:
		y_vals = []
		for scaled_im in scaled_ims:
			feed_dict = {x: numpy.stack([scaled_im])}
			feed_dict.update(dict(zip(params, param_vals)))
			y_vals.append(sess.run(y, feed_dict=feed_dict))

	count = 0
	for i, (scaled_im, y_val) in enumerate(zip(scaled_ims, y_vals)):
		for window_coords in numpy.argwhere(y_val[0, :, :, 0] > -math.log(1./0.99 - 1)):
			count = count + 1 #only care about number of boxes it can detect 
			
	print("COUNT: ", count)
	return count != 0


def original_img_hide_attack_color(im, param_vals):

	def perturb(img, param_vals):
		x_origin = tf.Variable(tf.zeros(img.shape))
		assign_origin_op = tf.assign(x_origin, img)

		#convert image to gray so it can pass through detect model 
		im_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) / 255.

		#resize colored image to match best scaled image shape 
		max_im_shape = detect_max_shape(im_gray, param_vals)
		im_color_resize = tf.squeeze(tf.image.resize_images(x_origin, (max_im_shape[0], max_im_shape[1])))
		
		img_gray = tf.image.rgb_to_grayscale(im_color_resize) #(250,250,1)
		im_gray = tf.squeeze(tf.cast(img_gray, numpy.float32)) #(250,250)

		input = tf.stack([im_gray]) #(1,250,250)

		_, y, params = model.get_detect_model(input)

		#mean over reduced probability for presence and letter detection, y[:,:,:,0] for just presence 
		y_mean = tf.reduce_mean(y)

		optim_step = tf.train.GradientDescentOptimizer(3).minimize(y_mean, var_list = [x_origin])
		adv = []

		#create bounds for how far the image can deviate 
		epsilon = tf.placeholder(tf.float32, ())
		below = img - epsilon
		above = img + epsilon 
		projected = tf.clip_by_value(tf.clip_by_value(x_origin, below, above), 0, 255)

		with tf.control_dependencies([projected]):
			project_step = tf.assign(x_origin, projected)

		#training 
		with tf.Session(config=tf.ConfigProto()) as sess:
			sess.run(assign_origin_op)
			feed_dict = {}
			feed_dict.update(dict(zip(params, param_vals)))
			for i in range(400):
				sess.run(optim_step,feed_dict = feed_dict)
				sess.run(project_step, feed_dict = {epsilon: 8000/255.0})
				print(sess.run(y_mean, feed_dict = feed_dict))
				if(isDetected(x_origin.eval().astype(numpy.uint8), param_vals) == False):
					break
			adv = (x_origin.eval().astype(numpy.uint8))

		return adv 


	return perturb(im, param_vals)


def _overlaps(match1, match2):
	bbox_tl1, bbox_br1, _, _ = match1
	bbox_tl2, bbox_br2, _, _ = match2
	return (bbox_br1[0] > bbox_tl2[0] and
			bbox_br2[0] > bbox_tl1[0] and
			bbox_br1[1] > bbox_tl2[1] and
			bbox_br2[1] > bbox_tl1[1])


def _group_overlapping_rectangles(matches):
	matches = list(matches)
	num_groups = 0
	match_to_group = {}
	for idx1 in range(len(matches)):
		for idx2 in range(idx1):
			if _overlaps(matches[idx1], matches[idx2]):
				match_to_group[idx1] = match_to_group[idx2]
				break
		else:
			match_to_group[idx1] = num_groups 
			num_groups += 1

	groups = collections.defaultdict(list)
	for idx, group in match_to_group.items():
		groups[group].append(matches[idx])

	return groups


def post_process(matches):
	"""
	Take an iterable of matches as returned by `detect` and merge duplicates.

	Merging consists of two steps:
	  - Finding sets of overlapping rectangles.
	  - Finding the intersection of those sets, along with the code
		corresponding with the rectangle with the highest presence parameter.

	"""
	groups = _group_overlapping_rectangles(matches)
	for group_matches in groups.values():
		mins = numpy.stack(numpy.array(m[0]) for m in group_matches)
		maxs = numpy.stack(numpy.array(m[1]) for m in group_matches)
		present_probs = numpy.array([m[2] for m in group_matches])
		letter_probs = numpy.stack(m[3] for m in group_matches)

		yield (numpy.max(mins, axis=0).flatten(),
			   numpy.min(maxs, axis=0).flatten(),
			   numpy.max(present_probs),
			   letter_probs[numpy.argmax(present_probs)])
def print_help():
	print("\nToo few arguments. Expected: 3")
	print("Usage: python detect.py [input_image] [weights] [output_image]\n")

def letter_probs_to_code(letter_probs):
	return "".join(common.CHARS[i] for i in numpy.argmax(letter_probs, axis=1))


if __name__ == "__main__":
    if(len(sys.argv)<4):
        print_help()
        exit()    
    
    f = numpy.load(sys.argv[2])
    param_vals = [f[n] for n in sorted(f.files, key=lambda s: int(s[4:]))]

    im = cv2.imread(sys.argv[1])

    img_color = original_img_hide_attack_color(im, param_vals)

    im_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY) / 255.
    #print(img_color)
    cv2.imwrite('perturbed' + sys.argv[3], img_color)
    for pt1, pt2, present_prob, letter_probs in post_process(
                                                  detect(im_gray, param_vals)):
        pt1 = tuple(reversed(map(int, pt1)))
        pt2 = tuple(reversed(map(int, pt2)))

        code = letter_probs_to_code(letter_probs)

        color = (0.0, 255.0, 0.0)
        cv2.rectangle(im, pt1, pt2, color)

        cv2.putText(im,
                    code,
                    pt1,
                    cv2.FONT_HERSHEY_PLAIN, 
                    1.5,
                    (0, 0, 0),
                    thickness=5)

        cv2.putText(im,
                    code,
                    pt1,
                    cv2.FONT_HERSHEY_PLAIN, 
                    1.5,
                    (255, 255, 255),
                    thickness=2)

    cv2.imwrite(sys.argv[3], im)
	

#!/usr/bin/env python
#
# Copyright (c) 2016 <NAME>
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
#     The above copyright notice and this permission notice shall be included
#     in all copies or substantial portions of the Software.
# 
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
#     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
#     NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
#     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
#     OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
#     USE OR OTHER DEALINGS IN THE SOFTWARE.


"""
Routines to detect number plates.

Use `detect` to detect all bounding boxes, and use `post_process` on the output
of `detect` to filter using non-maximum suppression.

"""


__all__ = (
	'detect',
	'post_process',
)


import collections
import itertools
import math
import sys

import cv2
import numpy
import tensorflow as tf

import common
import model

from detect_get_logits import get_attack_logits 

def make_scaled_ims(im, min_shape):
	ratio = 1. / 2 ** 0.5
	shape = (im.shape[0] / ratio, im.shape[1] / ratio)
	while True:
		shape = (int(shape[0] * ratio), int(shape[1] * ratio))
		if shape[0] < min_shape[0] or shape[1] < min_shape[1]:
			break
		yield cv2.resize(im, (shape[1], shape[0]))


def detect(im, param_vals):
    """
    Detect number plates in an image.

    :param im:
        Image to detect number plates in.

    :param param_vals:
        Model parameters to use. These are the parameters output by the `train`
        module.

    :returns:
        Iterable of `bbox_tl, bbox_br, letter_probs`, defining the bounding box
        top-left and bottom-right corners respectively, and a 7,36 matrix
        giving the probability distributions of each letter.

    """

    # Convert the image to various scales.
    scaled_ims = list(make_scaled_ims(im, model.WINDOW_SHAPE))
    #scaled_ims = hide_attack(im, param_vals)
    #print(scaled_ims[0].shape)

    # Load the model which detects number plates over a sliding window.
    x, y, params = model.get_detect_model()

    # Execute the model at each scale.
    with tf.Session(config=tf.ConfigProto()) as sess:
        y_vals = []
        for scaled_im in scaled_ims:
            feed_dict = {x: numpy.stack([scaled_im])}
            feed_dict.update(dict(zip(params, param_vals)))
            y_vals.append(sess.run(y, feed_dict=feed_dict))

    print(y_vals[0].shape)
    # Interpret the results in terms of bounding boxes in the input image.
    # Do this by identifying windows (at all scales) where the model predicts a
    # number plate has a greater than 50% probability of appearing.
    #
    # To obtain pixel coordinates, the window coordinates are scaled according
    # to the stride size, and pixel coordinates.
    count = 0
    for i, (scaled_im, y_val) in enumerate(zip(scaled_ims, y_vals)):
        for window_coords in numpy.argwhere(y_val[0, :, :, 0] >
                                                       -math.log(1./0.99 - 1)):

            count = count + 1
            letter_probs = (y_val[0,
                                  window_coords[0],
                                  window_coords[1], 1:].reshape(
                                    7, len(common.CHARS)))
            letter_probs = common.softmax(letter_probs)

            img_scale = float(im.shape[0]) / scaled_im.shape[0]

            bbox_tl = window_coords * (8, 4) * img_scale
            bbox_size = numpy.array(model.WINDOW_SHAPE) * img_scale

            present_prob = common.sigmoid(
                               y_val[0, window_coords[0], window_coords[1], 0])

            yield bbox_tl, bbox_tl + bbox_size, present_prob, letter_probs

    #print("Detected count: ", count) 

def detect_max_shape(im, param_vals):
    scaled_ims = list(make_scaled_ims(im, model.WINDOW_SHAPE))

    x, y, params = model.get_detect_model()

    # Execute the model at each scale.
    with tf.Session(config=tf.ConfigProto()) as sess:
        y_vals = []
        for scaled_im in scaled_ims:
            feed_dict = {x: numpy.stack([scaled_im])}
            feed_dict.update(dict(zip(params, param_vals)))
            y_vals.append(sess.run(y, feed_dict=feed_dict))

    # Interpret the results in terms of bounding boxes in the input image.
    # Do this by identifying windows (at all scales) where the model predicts a
    # number plate has a greater than 50% probability of appearing.
    #
    # To obtain pixel coordinates, the window coordinates are scaled according
    # to the stride size, and pixel coordinates.
    max_im = scaled_ims[0]
    max_prob = 0
    for i, (scaled_im, y_val) in enumerate(zip(scaled_ims, y_vals)):
        for window_coords in numpy.argwhere(y_val[0, :, :, 0] >
                                                       -math.log(1./0.99 - 1)):
            letter_probs = (y_val[0,
                                  window_coords[0],
                                  window_coords[1], 1:].reshape(
                                    7, len(common.CHARS)))
            letter_probs = common.softmax(letter_probs)

            img_scale = float(im.shape[0]) / scaled_im.shape[0]

            bbox_tl = window_coords * (8, 4) * img_scale
            bbox_size = numpy.array(model.WINDOW_SHAPE) * img_scale

            present_prob = common.sigmoid(
                               y_val[0, window_coords[0], window_coords[1], 0])

            if(present_prob > max_prob):
            	max_prob = present_prob
            	max_im = scaled_im 
    
    return max_im.shape

def isDetected(im, param_vals):
	im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) / 255.
	scaled_ims = list(make_scaled_ims(im_gray, model.WINDOW_SHAPE))
	x, y, params = model.get_detect_model()

	with tf.Session(config=tf.ConfigProto()) as sess:
		y_vals = []
		for scaled_im in scaled_ims:
			feed_dict = {x: numpy.stack([scaled_im])}
			feed_dict.update(dict(zip(params, param_vals)))
			y_vals.append(sess.run(y, feed_dict=feed_dict))

	count = 0
	for i, (scaled_im, y_val) in enumerate(zip(scaled_ims, y_vals)):
		for window_coords in numpy.argwhere(y_val[0, :, :, 0] > -math.log(1./0.99 - 1)):
			count = count + 1 #only care about number of boxes it can detect 
			
	print("COUNT: ", count)
	return count != 0


def original_img_hide_attack_color(im, param_vals):

	def perturb(img, param_vals):
		x_origin = tf.Variable(tf.zeros(img.shape))
		assign_origin_op = tf.assign(x_origin, img)

		#convert image to gray so it can pass through detect model 
		im_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) / 255.

		#resize colored image to match best scaled image shape 
		max_im_shape = detect_max_shape(im_gray, param_vals)
		im_color_resize = tf.squeeze(tf.image.resize_images(x_origin, (max_im_shape[0], max_im_shape[1])))
		
		img_gray = tf.image.rgb_to_grayscale(im_color_resize) #(250,250,1)
		im_gray = tf.squeeze(tf.cast(img_gray, numpy.float32)) #(250,250)

		input = tf.stack([im_gray]) #(1,250,250)

		_, y, params = model.get_detect_model(input)

		#mean over reduced probability for presence and letter detection, y[:,:,:,0] for just presence 
		y_mean = tf.reduce_mean(y)

		optim_step = tf.train.GradientDescentOptimizer(3).minimize(y_mean, var_list = [x_origin])
		adv = []

		#create bounds for how far the image can deviate 
		epsilon = tf.placeholder(tf.float32, ())
		below = img - epsilon
		above = img + epsilon 
		projected = tf.clip_by_value(tf.clip_by_value(x_origin, below, above), 0, 255)

		with tf.control_dependencies([projected]):
			project_step = tf.assign(x_origin, projected)

		#training 
		with tf.Session(config=tf.ConfigProto()) as sess:
			sess.run(assign_origin_op)
			feed_dict = {}
			feed_dict.update(dict(zip(params, param_vals)))
			for i in range(400):
				sess.run(optim_step,feed_dict = feed_dict)
				sess.run(project_step, feed_dict = {epsilon: 8000/255.0})
				print(sess.run(y_mean, feed_dict = feed_dict))
				if(isDetected(x_origin.eval().astype(numpy.uint8), param_vals) == False):
					break
			adv = (x_origin.eval().astype(numpy.uint8))

		return adv 


	return perturb(im, param_vals)


def _overlaps(match1, match2):
	bbox_tl1, bbox_br1, _, _ = match1
	bbox_tl2, bbox_br2, _, _ = match2
	return (bbox_br1[0] > bbox_tl2[0] and
			bbox_br2[0] > bbox_tl1[0] and
			bbox_br1[1] > bbox_tl2[1] and
			bbox_br2[1] > bbox_tl1[1])


def _group_overlapping_rectangles(matches):
	matches = list(matches)
	num_groups = 0
	match_to_group = {}
	for idx1 in range(len(matches)):
		for idx2 in range(idx1):
			if _overlaps(matches[idx1], matches[idx2]):
				match_to_group[idx1] = match_to_group[idx2]
				break
		else:
			match_to_group[idx1] = num_groups 
			num_groups += 1

	groups = collections.defaultdict(list)
	for idx, group in match_to_group.items():
		groups[group].append(matches[idx])

	return groups


def post_process(matches):
	"""
	Take an iterable of matches as returned by `detect` and merge duplicates.

	Merging consists of two steps:
	  - Finding sets of overlapping rectangles.
	  - Finding the intersection of those sets, along with the code
		corresponding with the rectangle with the highest presence parameter.

	"""
	groups = _group_overlapping_rectangles(matches)
	for group_matches in groups.values():
		mins = numpy.stack(numpy.array(m[0]) for m in group_matches)
		maxs = numpy.stack(numpy.array(m[1]) for m in group_matches)
		present_probs = numpy.array([m[2] for m in group_matches])
		letter_probs = numpy.stack(m[3] for m in group_matches)

		yield (numpy.max(mins, axis=0).flatten(),
			   numpy.min(maxs, axis=0).flatten(),
			   numpy.max(present_probs),
			   letter_probs[numpy.argmax(present_probs)])
def print_help():
	print("\nToo few arguments. Expected: 3")
	print("Usage: python detect.py [input_image] [weights] [output_image]\n")

def letter_probs_to_code(letter_probs):
	return "".join(common.CHARS[i] for i in numpy.argmax(letter_probs, axis=1))


if __name__ == "__main__":
    if(len(sys.argv)<4):
        print_help()
        exit()    
    
    f = numpy.load(sys.argv[2])
    param_vals = [f[n] for n in sorted(f.files, key=lambda s: int(s[4:]))]

    im = cv2.imread(sys.argv[1])

    img_color = original_img_hide_attack_color(im, param_vals)

    im_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY) / 255.
    #print(img_color)
    cv2.imwrite('perturbed' + sys.argv[3], img_color)
    for pt1, pt2, present_prob, letter_probs in post_process(
                                                  detect(im_gray, param_vals)):
        pt1 = tuple(reversed(map(int, pt1)))
        pt2 = tuple(reversed(map(int, pt2)))

        code = letter_probs_to_code(letter_probs)

        color = (0.0, 255.0, 0.0)
        cv2.rectangle(im, pt1, pt2, color)

        cv2.putText(im,
                    code,
                    pt1,
                    cv2.FONT_HERSHEY_PLAIN, 
                    1.5,
                    (0, 0, 0),
                    thickness=5)

        cv2.putText(im,
                    code,
                    pt1,
                    cv2.FONT_HERSHEY_PLAIN, 
                    1.5,
                    (255, 255, 255),
                    thickness=2)

    cv2.imwrite(sys.argv[3], im)
#!/usr/bin/env python # # Copyright (c) 2016 <NAME> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # #     The above copyright notice and this permission notice shall be included #     in all copies or substantial portions of the Software. # #     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS #     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF #     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN #     NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, #     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR #     OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE #     USE OR OTHER DEALINGS IN THE SOFTWARE. Routines to detect number plates.  Use `detect` to detect all bounding boxes, and use `post_process` on the output of `detect` to filter using non-maximum suppression. Detect number plates in an image.      :param im:         Image to detect number plates in.      :param param_vals:         Model parameters to use. These are the parameters output by the `train`         module.      :returns:         Iterable of `bbox_tl, bbox_br, letter_probs`, defining the bounding box         top-left and bottom-right corners respectively, and a 7,36 matrix         giving the probability distributions of each letter. # Convert the image to various scales. #scaled_ims = hide_attack(im, param_vals) #print(scaled_ims[0].shape) # Load the model which detects number plates over a sliding window. # Execute the model at each scale. # Interpret the results in terms of bounding boxes in the input image. # Do this by identifying windows (at all scales) where the model predicts a # number plate has a greater than 50% probability of appearing. # # To obtain pixel coordinates, the window coordinates are scaled according # to the stride size, and pixel coordinates. #print("Detected count: ", count) # Execute the model at each scale. # Interpret the results in terms of bounding boxes in the input image. # Do this by identifying windows (at all scales) where the model predicts a # number plate has a greater than 50% probability of appearing. # # To obtain pixel coordinates, the window coordinates are scaled according # to the stride size, and pixel coordinates. #only care about number of boxes it can detect #convert image to gray so it can pass through detect model #resize colored image to match best scaled image shape #(250,250,1) #(250,250) #(1,250,250) #mean over reduced probability for presence and letter detection, y[:,:,:,0] for just presence #create bounds for how far the image can deviate #training Take an iterable of matches as returned by `detect` and merge duplicates.  	Merging consists of two steps: 	  - Finding sets of overlapping rectangles. 	  - Finding the intersection of those sets, along with the code 		corresponding with the rectangle with the highest presence parameter. #print(img_color)