0

For a computer science class, I'm supposed to write a program that will find the position and the size of an unknown number of aliens in a picture like this one: http://www-bcf.usc.edu/~stejada/csci101/Pix/MARS2.jpg. I currently have the following code:

#include "Myro.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include "alien.h"
#include <vector>

using std::cout;
using std::cin;
using std::endl;
using std::vector;

void trackBlob(PicturePtr &aPic, int x, int y);
int BlobSize(PicturePtr &aPic, int x, int y, vector<int>& xLocs, vector<int>& yLocs);

vector<alien> found;
int returned;

int main()
{
returned = 0;
cout << "Pick a picture to search 0-5, or choose 6 to quit" << endl;
int selection;
cin >> selection;
PicturePtr thePic;

// Choose a picture to search
bool selecting = true;
while (selecting) {
    switch (selection) {
        case 0:
            thePic = makePicture("MARS.jpg");
            selecting = false;
            break;
        case 1:
            thePic = makePicture("MARS1.jpg");
            selecting = false;
            break;
        case 2:
            thePic = makePicture("MARS2.jpg");
            selecting = false;
            break;
        case 3:
            thePic = makePicture("MARS3.jpg");
            selecting = false;
            break;
        case 4:
            thePic = makePicture("MARS4.jpg");
            selecting = false;
            break;
        case 5:
            thePic = makePicture("MARS6.jpg");
            selecting = false;
            break;
        case 6:
            cout << "Terminating." << endl;
            return 0;
        default:
            cout << "Invalid input. Please try again." << endl << endl;
            break;
    }// end switch
} // end while

// Find the aliens
cout << endl;
cout << "Pic size: " << getHeight(thePic) * getWidth(thePic) << endl << endl;
int numGreen = 0;
for (int i = 0; i < getWidth(thePic); i++) {
    for (int j = 0; j < getHeight(thePic); j++) {
        Pixel pix;
        pix = getPixel(thePic,i,j);

        // Check for alien color
        if (pix.R >= 100 && pix.R <= 120 && pix.G >= 240 && pix.G <= 255 && pix.B >= 1 && pix.B <= 15) {
            trackBlob(thePic,i,j);
            numGreen++;
        }
        else if (pix.R >= 165 && pix.R <= 185 && pix.G >= 215 && pix.G <= 235 && pix.B >= 65 && pix.B <= 85) {
            trackBlob(thePic,i,j);
            numGreen++;
        }
        else if (pix.R >= 130 && pix.R <= 155 && pix.G >= 210 && pix.G <= 230 && pix.B >= 145 && pix.B <= 175) {
            trackBlob(thePic,i,j);
            numGreen;
        }
        else if (pix.R >= 27 && pix.R <= 47 && pix.G <= 265 && pix.G >= 245 && pix.B >= 1 && pix.B <= 10) {
            trackBlob(thePic,i,j);
            numGreen++;
        }
        else if (pix.R >= 240 && pix.R <= 255 && pix.G <= 240 && pix.G >= 255 && pix.B >= 25 && pix.B <= 45) {
            trackBlob(thePic,i,j);
            numGreen++;
        }
        else if (pix.R >= 235 && pix.R <= 255 && pix.G <= 245 && pix.G >= 210 && pix.B >= 200 && pix.B <= 230) {
            trackBlob(thePic,i,j);
            numGreen++;
        }
        else if (pix.R <= 240 && pix.R >= 210 && pix.G <=255 && pix.G >= 240 && pix.B >= 1 && pix.B <= 10) {
            trackBlob(thePic,i,j);
            numGreen++;
        }
    }
}
cout << endl << endl;
cout << "Number of Aliens: " << found.size() << endl;
for (int n = 0; n < found.size(); n++) {
    cout << "Position of Alien #" << n << ": (" << found[n].x << "," << found[n].y << ")" << endl;
    cout << "Size of Alien #" << n << ": " << found[n].size << endl;
}

cout << endl << endl << "Number pixels tried: " << numGreen << endl << endl;
cout << "Times blob returned: " << returned << endl;
show(thePic);
return 0;
}

void trackBlob(PicturePtr &aPic, int x, int y) {
// Just to be safe
Pixel aPixel = getPixel(aPic,x,y);
//if (aPixel.R == 0 && aPixel.G == 0 && aPixel.B == 0)
    //return;

// Find the size of the alien
vector<int> xLocs;
vector<int> yLocs;
int size = BlobSize(aPic,x,y,xLocs,yLocs);
cout << "Blob size: " << size << endl;
returned++;

// Make sure it's big enough to be an alien
if (size < 5) {
    return;
}

alien newAlien;

// Find the position
newAlien.x = 0;
for (int i = 0; i < xLocs.size(); i++) {
    newAlien.x += xLocs[i];
}
newAlien.x = newAlien.x/xLocs.size();

newAlien.y = 0;
for (int j = 0; j < yLocs.size(); j++) {
    newAlien.y += yLocs[j];
}
newAlien.y = newAlien.y/yLocs.size();

found.push_back(newAlien);
}

int BlobSize(PicturePtr &aPic, int x, int y, vector<int>& xLocs, vector<int>& yLocs)
{
if (x >= getWidth(aPic) || x < 0)
    return 0;

Pixel pix = getPixel(aPic,x,y);

// Just to be safe
//if (pix.R == 0 && pix.G == 0 && pix.B == 0)
    //return 0;

bool isAlien = false;
if (pix.R >= 100 && pix.R <= 120 && pix.G >= 240 && pix.G <= 255 && pix.B >= 1 && pix.B <= 15)
    isAlien = true;
else if (pix.R >= 165 && pix.R <= 185 && pix.G >= 215 && pix.G <= 235 && pix.B >= 65 && pix.B <= 85)
    isAlien = true;
else if (pix.R >= 130 && pix.R <= 155 && pix.G >= 210 && pix.G <= 230 && pix.B >= 145 && pix.B <= 175)
    isAlien = true;
else if (pix.R >= 27 && pix.R <= 47 && pix.G <= 265 && pix.G >= 245 && pix.B >= 1 && pix.B <= 10)
    isAlien = true;
else if (pix.R >= 240 && pix.R <= 255 && pix.G <= 240 && pix.G >= 255 && pix.B >= 25 && pix.B <= 45)
    isAlien = true;
else if (pix.R >= 235 && pix.R <= 255 && pix.G <= 245 && pix.G >= 210 && pix.B >= 200 && pix.B <= 230)
    isAlien = true;
else if (pix.R <= 240 && pix.R >= 210 && pix.G <=255 && pix.G >= 240 && pix.B >= 1 && pix.B <= 10)
    isAlien = true;

if (!isAlien)
    return 0;

// Store the location in the position vectors
xLocs.push_back(x);
yLocs.push_back(y);

// Make sure the pixel doesn't get counted again
setPixelColor(aPic,x,y,0,0,0);

int size = 0;

for (int i = 0; i <= 2; i++) {
    for (int j = 0; j <= 2; j++) {
        if (i == 0 && j == 0) {
            break;
        }
        size += BlobSize(aPic,x + (i-1), y + (j-1),xLocs,yLocs);
    }
}

return 1 + size;
}

When I run the code, it says it's found several hundred "aliens." Each one it finds is bigger than the last if that's helpful. I've been staring at this for days and have no idea what's going wrong. Any help would be much appreciated.

Thanks!

  • Can you add an self-contained small example with sample input ? – mmgp Dec 03 '12 at 20:26
  • Do you mean an example of the output from analyzing one picture? – user1675330 Dec 03 '12 at 20:27
  • I meant a self-contained code and also one of those MARS.JPG pictures, including the exact result you get and what you expected to get. The code you posted depends on some "alien.h", "Myro.h", etc, that is not self-contained. – mmgp Dec 03 '12 at 20:41
  • The "alien" class just has three variables - (position) x,y, and size. The Myro library is the way of accessing the picture, so it can't really be integrated to the code. PicturePtr is the picture object. Most operations are done by acquiring a Pixel from a coordinate in the picture, mostly the RGB values.Using this picture: http://www-bcf.usc.edu/~stejada/csci101/Pix/MARS1.jpg, the program successfully changes almost all of the pixels on the alien to black, but lists 214 aliens as found. It should only have one. The sizes of the aliens run from about 300 to 1400. – user1675330 Dec 03 '12 at 23:46
  • With the input picture at bcf.usc.edu/~stejada/csci101/Pix/MARS1.jpg, I get an output image of docs.google.com/open?id=0B79nx_a6UPX6bDV4RTl3bVJWTTA For the process: For every pixel in the image, check to see if it's a color I'm interested in (on). If it's off, move to the next pixel. If it's on, track the blob. Recursively check each surrounding pixel and return 1 + the size of all surrounding pixels. If a pixel is off, it returns 0. Every time a pixel is checked, its color is changed to black to prevent it from being checked again. – user1675330 Dec 04 '12 at 02:19
  • Ok. Almost good now. So, your code specifically checks for the green color in the alien hoping such thing doesn't appear anywhere else in the image. I will suppose that holds for your problem. Now, there is clearly some problem with your code if I understood all that you said. After you find the first green alien pixel, all of the interior points should be turned to black. But that is clearly not the case as can be seen in your output, there are many small green regions. So, the fact that there are all those small regions is the reason you get multiple aliens? Or am I still missing something ? – mmgp Dec 04 '12 at 02:26
  • I'm not entirely sure. I know that at the end of the program, virtually all the green pixels have been turned black, so they all get checked at some point. It does look like some or all are being checked more than once, but I don't know why. – user1675330 Dec 04 '12 at 05:03
  • Well, that is relatively easy to understand why. You want to call trackBlob only once, since there is only one alien in your image. But you call it multiple times and that is why you have multiple aliens. Now, one of the reasons you call it multiple times is either: a) your code for checking for aliens is too restricted (i.e., it stops considering the blob too early), b) there is some coding error. BlobSize is actually a flood fill, and it duplicates the code in the main function. Rewrite both pieces of code so you no longer have duplicate code, making it easier to spot errors. – mmgp Dec 04 '12 at 14:13

1 Answers1

4

First off, you should remove the comments from BlobSize() like so:

// So pixels aren't counted twice
if (pix.R == 0 && pix.G == 0 && pix.B == 0)
    return 0;

Since BlobSize() changes the counted pixels to black, you need to keep those lines in your code so it doesn't count pixels twice.

Also, your for loop at the end of BlobSize() is slightly wrong. It should look like this:

for (int i = -1; i <= 1; i++) {
    for (int j = -1; j <= 1; j++) {
        // skip pixel at this location
        if (i == 0 && j == 0) {
            continue;
        }
        size += BlobSize(aPic,x + (i-1), y + (j-1),xLocs,yLocs);
    }
}

The way that it was before would check the pixel one above and left of the pixel at the current location, see that i == 0 && j == 0, then skip checking the first column. The program would run BlobSize() on the other 6 pixels (including the one at the current location).

By the way, nice use of vectors and recursion. Sorry if I answered too late and you already turned it in. I'm turning mine in on Sunday because of the extension.