user11615
user11615

Reputation: 51

How to detect similar color regions in an image?

I have created a simple program to generate random images, giving random colors to each pixel. I know that there is a very low chance of generating a reconocible image but I would like to try.

I have observed that the longest part of the work is to check if the images are really something. I also observed that most of the images produced are just fields of colorful images with lots of individual pixels. That's why I would like to ask for an algorithm in pseudocode to detect similar color regions in an image. I think that the easiest way to find meaningful images is to filter all those random pixel images. It's not perfect but I think it will help. If someone could propose another kind of filtering algorithm that would help with this task I would also apreciate it.

(edited)

To clarify this, in case my explanation was not clear enough, I will show you some images:

This is the kind of images I'm getting, basically I would describe it as "Colorful noise". As you can see, all the pixels are spread individually without grouping in similar color regions to hopfully create shapes of objects or anything reconocible as something.

In here you can see a conventional image, a "reconocible" picture. We can clearly see a dog lying on the grass with a tennis ball. If you observe carefully this picture it can be clearly distinguished from the other one because it has agrupations of similar colors which we can difer (as the dog, a white region, the grass, a dark green region, and the tenis ball, a light green region).

What I exactly want is to remove the "pixelly" images before saving them in the HD and only save the ones with color agrupations. As I said before, this idea is the best I had to filter these randomly generated images but if someone proposes another more efficient way I would really apreciate it.

(edited)

Ok, I think that this post is becoming too long... Well if someone want's to have a look here is the code of the program I wrote. It's really straightforward. I've program it in Python using Pygame. I know that this isn't nearly the most efficient way to do it, I'm aware of that. The thing is that I'm quite a noob in this field and I don't really know another way to do this in other languages or modules. Maybe you could help me also with this... I don't know, maybe translate the code to C++? I'm feeling that I'm asking for to many questions in the same post but, as I sayd tons of times, any help would be greatly apreciated.

import pygame, random
pygame.init()

#lots of printed text statements here

imageX = int(input("Enter the widht of the image you want to produce: "))
imageY = int(input("Enter the height of the image you want to produce: "))
maxImages = int(input("Enter the maximun image amoungt you want to produce: "))
maxMem = int(input("Enter the maximun data you want to produce (MB, only works with     800x600 images): "))
maxPPS = int(input("Enter the maximun image amoungt you want to produce each second: "))
firstSeed = int(input("Enter the first seed you want to use: "))

print("\n\n\n\n")

seed = firstSeed
clock = pygame.time.Clock()
images = 0
keepGoing = True

while keepGoing:

    #seed
    random.seed(seed)

    #PPS
    clock.tick(maxPPS)

    #surface
    image = pygame.Surface((imageX,imageY))

    #generation
    for x in range(imageX):
        for y in range(imageY):
            red = random.randint(0,255)
            green = random.randint(0,255)
            blue = random.randint(0,255)

            image.set_at((x,y),(red,green,blue))

    #save
    pygame.image.save(image,str(seed)+".png")

    #update parameters
    seed += 1
    images += 1

    #print seed
    print(seed - 1)

    #check end
    if images >= maxImages:
        keepGoing = False
    elif (images * 1.37) >= maxMem:
        keepGoing = False

    pygame.event.pump()


print("\n\nThis is the last seed that was used: " + str(seed - 1))
input("\nPress Enter to exit")

Upvotes: 1

Views: 5331

Answers (3)

Jason
Jason

Reputation: 286

Here is a butchered algorithm for you to try (try it in OpenCV):

  1. Get image
  2. Work with just one color dimension of the image i.e. Red or Green... or Gray ...or do the following for each separately
  3. Sum up all the values in the image and save this as the "energy" value of the image
  4. Use OpenCV's Smooth function to blur the image
  5. The trick to blurring the image correctly is to choose the size of the kernel (aka filter) to be smaller than the width of important features and larger than the unimportant or noisy features. The size is controlled by defining param1 and param2. See http://opencv.willowgarage.com/documentation/python/imgproc_image_filtering.html
  6. Now for the output, sum up all the values to get the output "energy"
  7. Keep image if the output has at least half of the energy of the input. Technically the trick in number 5 is the same as choosing 50 percent as the threshold to keep or discard images. So changing the threshold here is approximately the same as changing the filter size.
  8. Optional. No need to think too much about it though, just get these energy values for some set of the images and choose the threshold by eye.

What is happening? Your filtering out high frequencies then seeing if there is still something left over. Most images have lots of energy at lower spatial frequencies. In fact jpeg compression uses this fact to compress images. The filter must have an energy of one to work correctly, so I'm assuming that this is true.

Hope this helps!

Upvotes: 1

zimady
zimady

Reputation: 137

Without knowing exactly what you're trying to achieve, it's difficult to offer specific help. But, reading your account did remind me of something I saw recently which, whilst quite different in implementation, has a similar end goal: generate a recognisable image from randomness.

Check out https://github.com/phl/pareidoloop by Philip McCarthy.

Philip's project starts with random polygons and the algorithm favours face like images. Two key points here: the polygons significantly reduce the amount of random noise right off the bat so the chances of generating something recognisable are significantly increased. Secondly, the algorithm favours a specific type of recognisable image: I suspect you're going to have to work towards a specific type of image so that you have some parameters with which to computationally estimate "recognisability".

hth!

Upvotes: 0

av501
av501

Reputation: 6729

The simplest way of filtering out noise is to look for correlation. Nearby regions should be highly correlated in most of the image. There are so many ways to do it.

You should use a combination of the following and do some tweaking to find parameters to get acceptable hit/miss ratio

Color correlation: You will find huge amount of correlation in U/V in nearby regions in "proper" images.

Edge detection: Natural images tend to have well defined edges. easiest way to detect noise from natural images is to do this.

Quite bit more can be done: Frequency analysis: Noisy images will have all frequencies natural images have huge peaks usually. scale space analysis etc depending on how complex you want to get.. how much hit ratio you are willing to tolerate. In general trying to get recognizable images is an open ended topic but you should be able to get very high hit ratio if you specifically wanting to remove out noise images like the one you gave in the example.

EDIT: In general there is no exact algorithms for problems like this. You have to make assumptions about properties of underlying data. Then use basic primitives (correlation, frequency domain data, edges etc) and combine it to give your algorithm for solving the problem. This is because the solution to problems like this is very data specific. Quite different than solving say Computer science algorithms. This is not to say that signal processing algorithms don't have exactness. However your current problem and many others deal with what is known as Random Variables and Stochastic Processes. You may have to search if someone has tried to solve this problem in literature or at some university. You can use that as your starting point. Tweak that algorithm to suite you. However you are not going to get a solution easily unless you take some time to understand some of the things I mentioned and are willing to do some experiments and emperical analysis.

Upvotes: 0

Related Questions