2

I am trying to write a code using c++ and opencv that would recognize which blue pixel comes first from left, right, up and bottom. The picture I am using is this one: blue lines on image

And what I want to receive is a picture like this: blue lines with extrema marked

This is my code until now and I don't really understand why it doesn't work.

    void findBluePixels(Mat& original, Point2f min_x, Point2f max_x, Point2f min_y, Point2f max_y) {
    //First I set every point to the beginning of the image
        min_x = Point(0, 0);
        max_x = Point(0, 0);
        min_y = Point(0, 0);
        max_y = Point(0, 0);
    //looking for the most left blue pixel (the blue pixel with the smallest x value)
    //we are going through every column and every row
        for (int col = 0; col < original.cols; col++) {
            for (int row = 0; row < original.rows; row++) {
    //we check for every pixel if the pixel is blue and if the column of the pixel is bigger or equal to the beginning of the image
    if (original.at<Vec3b>(row, col)[0] == 255 && 
    original.at<Vec3b>(row, col)[1] == 0 &&
 original.at<Vec3b>(row, col)[2] == 0 && col >= min_x.y) {
    //if yes we have new value for the min_x and we stop looking because we have found the most left blue pixel
        min_x = Point(row, col);
        break;
                }
            }
        }
    //looking for the most right blue pixel (the blue pixel with the biggest x value)
    //we are going through every column and every row
        for (int col = 0; col < original.cols; col++) {
            for (int row = 0; row < original.rows; row++) {
    //we check for every pixel if the pixel is blue and if the column of the pixel is bigger or equal to the beginning of the image
    if (original.at<Vec3b>(row, col)[0] == 255 && 
    original.at<Vec3b>(row, col)[1] == 0 && 
original.at<Vec3b>(row, col)[2] == 0 && col >= max_x.y) {
    //if yes we have new value for the max_x, but we don't break because we are looking for the biggest blue pixel
    //we continue to search until the end of the picture
    max_x = Point(row, col);
                }
            }
        }
    //looking for the highest blue pixel (the blue pixel with the smallest y value)
    //we are going through every row and every column
        for (int row = 0; row < original.rows; row++) {
            for (int col = 0; col < original.cols; col++) {
    //we check for every pixel if the pixel is blue and if the row of the pixel is bigger or equal to the beginning of the image
    if (original.at<Vec3b>(row, col)[0] == 255 && 
    original.at<Vec3b>(row, col)[1] == 0 &&
    original.at<Vec3b>(row, col)[2] == 0 && row >= min_y.x) {
    //if yes we have new value for the min_y and we stop looking because we have found the highest blue pixel
    min_y = Point(row, col);
    break;
                }
            }
        }
    //looking for the most down blue pixel (the blue pixel with the biggest y value)
    //we are going through every column and every row
        for (int row = 0; row < original.rows; row++) {
            for (int col = 0; col < original.cols; col++) {
    //we check for every pixel if the pixel is blue and if the row of the pixel is bigger or equal to the beginning of the image
    if (original.at<Vec3b>(row, col)[0] == 255 && 
    original.at<Vec3b>(row, col)[1] == 0 &&
    original.at<Vec3b>(row, col)[2] == 0 && row >= max_y.x) {
    //if yes we have new value for the max_y, but we don't break because we are looking for the biggest blue pixel
    //we continue to search until the end of the picture
    max_y = Point(row, col);
                }
            }
        }
    //Here I want to make green points on the pixels we have found
    circle(original, min_x, 3, Scalar(0, 255, 0), 8, LINE_AA);
    circle(original, max_x, 3, Scalar(0, 255, 0), 8, LINE_AA);
    circle(original, min_y, 3, Scalar(0, 255, 0), 8, LINE_AA);
    circle(original, max_y, 3, Scalar(0, 255, 0), 8, LINE_AA);
}

The dots I receive at the end are totaly random.

I would really appreciate it if someone can help! :)

VanesaZ
  • 23
  • 2
  • 1
    dunno, but you should extract a function `bool is_blue( const Pixel &)` to make the code more readable and concise. – Vorac Jul 11 '19 at 07:23
  • Sorry, but your logic seems totally random to me. Anyway this is what debuggers are for, use one to find exactly when and where your program diverges from your expectations. – john Jul 11 '19 at 07:26
  • You didn't specify your coordinate system in the post, which makes it hard to be sure. But `col >= max_x.y` compares a column, which I would consider to be an x coordinate, with a y coordinate. That's meaningless. Same issue with all the other comparisons, you seem to be mixing up x and y. – john Jul 11 '19 at 07:28
  • Something is wrong with your notation.. If x goes from left to right and y from up to bottom (or the other way round, w/e), `col` corresponds to your x value and `row` to the y value. If that is not your intended notation, the definition of leftmost and rightmost are wrong. – nnolte Jul 11 '19 at 07:30
  • Your code for `min_x` and `max_x` is identical. Messed up `>=` and `<=` somewhere. – IcedLance Jul 11 '19 at 08:10
  • One thing that bothers me is that you scan image 4 times when once would be enough. For each point you just check every blue pixel if it's more (higher, lower, lefter, righter) than the already remembered pixels you set the new value. Very similar than looking for maximum value in non sorted array. Also please use proper indentation. – Anže Jul 11 '19 at 08:25

2 Answers2

3

As @nivpeled mentioned, but in code.

void findBluePixels(Mat& original) {
    Point min_x = Point(original.cols, original.rows);
    Point min_y = Point(original.cols, original.rows);
    Point max_x = Point(-1, -1);
    Point max_y = Point(-1, -1);
    //looking for the most left blue pixel (the blue pixel with the smallest x value)
    //we are going through every column and every row

    const Vec3b blueColor(255, 0, 0);
    for (int row = 0; row < original.rows; row++) {
        for (int col = 0; col < original.cols; col++) {
            if (blueColor != original.at<Vec3b>(row, col))
                continue;

            if (min_x.x > col) {
                min_x = Point(col, row);
            }
            if (max_x.x < col) {
                max_x = Point(col, row);
            }

            if (min_y.y > row) {
                min_y = Point(col, row);
            }
            if (max_y.y < row) {
                max_y = Point(col, row);
            }
        }
    }
    //Here I want to make green points on the pixels we have found
    circle(original, min_x, 13, Scalar(0, 255, 0), 8, LINE_AA);
    circle(original, max_x, 13, Scalar(0, 255, 0), 8, LINE_AA);
    circle(original, min_y, 13, Scalar(0, 255, 0), 8, LINE_AA);
    circle(original, max_y, 13, Scalar(0, 255, 0), 8, LINE_AA);
}

result

Plus some recommendations:

• Do for loop first for row, then for column. Computer works much faster if you access to data sequentially. Example access sequence numbered:

Faster ->
[ 1 2 3 ] 
[ 4 5 6 ] 
[ 7 8 9 ] 
Slower ->
[ 1 4 7 ] 
[ 2 5 8 ] 
[ 3 6 9 ]
Gralex
  • 4,285
  • 7
  • 26
  • 47
1
  1. You shall loop on the matrix only once and do all the checks within the same (inner) for loop body.

  2. Prefer using names rather than numbers. e.g. if (original.at(row, col)[BLUE] == 255 instead of if (original.at(row, col)[0] == 255

  3. Please double check index 0 in the pixel indeed hold the blue value (isn't it RGB?)

  4. logic problems: if you want to find e.g. minimal x, you shall code (col < min_x.y):

    if (... && col < min_x.y) {
    min_x = Point(row, col); break; }

and init as follows:

min_x = Point(MAX_COL, 0);
max_x = Point(MIN_COL, 0);
min_y = Point(0, MAX_ROW);
max_y = Point(0, MIN_ROW);
nivpeled
  • 1,810
  • 5
  • 17