Search code examples
pythonimage-processingcomputer-visionpython-imaging-libraryimage-comparison

Detecting a Specific Watermark in a Photo with Python (without SciPy)


I have a large number of images (hundreds of thousands) and, for each one, I need to say whether or not it has a watermark in the top right corner. The watermark is always the same and is in the same position. It takes the form of a ribbon with a symbol and some text. I'm looking for simple and fast way to do this that, ideally, doesn't use SciPy (as it's not available on the server I'm using -- but it can use NumPy)

So far, I've tried using PIL and the crop function to isolate the area of the image where the watermark should be and then compared the histograms with a RMS function (see http://snipplr.com/view/757/compare-two-pil-images-in-python/). That doesn't work very well as there are lots of errors in both directions.

Any ideas would be much appreciated. Thanks


Solution

  • Another possibility is to use machine learning. My background is natural language processing (not computer vision), but I tried creating a training and testing set using the description of your problem and it seems to work (100% accuracy on unseen data).

    Training set

    The training set consisted of the same images with the watermark (positive example), and without the watermark (negative example).

    Testing set

    The testing set consists of images that were not in the training set.

    Example data

    If interested, you can try it with the example training and testing images.

    Code:

    Full version available as a gist. Excerpt below:

    import glob
    
    from classify import MultinomialNB
    from PIL import Image
    
    
    TRAINING_POSITIVE = 'training-positive/*.jpg'
    TRAINING_NEGATIVE = 'training-negative/*.jpg'
    TEST_POSITIVE = 'test-positive/*.jpg'
    TEST_NEGATIVE = 'test-negative/*.jpg'
    
    # How many pixels to grab from the top-right of image.
    CROP_WIDTH, CROP_HEIGHT = 100, 100
    RESIZED = (16, 16)
    
    
    def get_image_data(infile):
        image = Image.open(infile)
        width, height = image.size
        # left upper right lower
        box = width - CROP_WIDTH, 0, width, CROP_HEIGHT
        region = image.crop(box)
        resized = region.resize(RESIZED)
        data = resized.getdata()
        # Convert RGB to simple averaged value.
        data = [sum(pixel) / 3 for pixel in data]
        # Combine location and value.
        values = []
        for location, value in enumerate(data):
            values.extend([location] * value)
        return values
    
    
    def main():
        watermark = MultinomialNB()
        # Training
        count = 0
        for infile in glob.glob(TRAINING_POSITIVE):
            data = get_image_data(infile)
            watermark.train((data, 'positive'))
            count += 1
            print 'Training', count
        for infile in glob.glob(TRAINING_NEGATIVE):
            data = get_image_data(infile)
            watermark.train((data, 'negative'))
            count += 1
            print 'Training', count
        # Testing
        correct, total = 0, 0
        for infile in glob.glob(TEST_POSITIVE):
            data = get_image_data(infile)
            prediction = watermark.classify(data)
            if prediction.label == 'positive':
                correct += 1
            total += 1
            print 'Testing ({0} / {1})'.format(correct, total)
        for infile in glob.glob(TEST_NEGATIVE):
            data = get_image_data(infile)
            prediction = watermark.classify(data)
            if prediction.label == 'negative':
                correct += 1
            total += 1
            print 'Testing ({0} / {1})'.format(correct, total)
        print 'Got', correct, 'out of', total, 'correct'
    
    
    if __name__ == '__main__':
        main()
    

    Example output

    Training 1
    Training 2
    Training 3
    Training 4
    Training 5
    Training 6
    Training 7
    Training 8
    Training 9
    Training 10
    Training 11
    Training 12
    Training 13
    Training 14
    Testing (1 / 1)
    Testing (2 / 2)
    Testing (3 / 3)
    Testing (4 / 4)
    Testing (5 / 5)
    Testing (6 / 6)
    Testing (7 / 7)
    Testing (8 / 8)
    Testing (9 / 9)
    Testing (10 / 10)
    Got 10 out of 10 correct
    [Finished in 3.5s]