1

My code is using OPENCV for image processing and I want to randomly create a feature set of points which are white. The program results in Assertion failed error when running the inner WHILE LOOP SECOND TIME. I have commented and tested the program to find exactly where is the problem. And i have found the problem with image.at(b,a) part of the code. It fails to run the second time. Although it runs perfectly fine the first time.
If i run the code with constant value instead of Variables b,a in the inner while loop, or with (j,j) variables it runs. I have used fout to print some debug statements. I am also attaching the .txt file output to help you see what's happening.

START OF THE OUTPUT FROM TXT FILE

start of while loop

inside the while loop

outside the while loop

[255, 255, 255]404 1173 start of the while loop

inside the while loop

END OF THE OUTPUT FROM TXT FILE

Pretty strange.Please help me figure this out!! I am pasting my code:

int main() {
    int i = 0;
    int a;
    ofstream fout("test.txt");
    int b;
    int j = 0;
    cv::Mat img;
    cv::Scalar* scalar_low;
    cv::Scalar* scalar_up;
    cv::Mat newimg;
    cv::Mat img2;
    stringstream ss;
    string s;
    scalar_low = new cv::Scalar(0, 30, 60);
    scalar_up = new cv::Scalar(20, 150, 255);
    int imgwidth;
    int imgheight;
    srand(112);
    while (j <= 45)
    {
    s="imagedata\\test"+ to_string(j);    
    s+=".jpg";
    img=imread(s);    
    cvtColor(img, img2, CV_BGR2HSV, 0);
    inRange(img2, *scalar_low, *scalar_up, newimg);            
    s="imagedata\\result"+ to_string(j);
    s+=".jpg";
    imwrite(s, newimg);
    imgwidth = newimg.cols;
    imgheight = newimg.rows;
    i = 0;
    while (i <= 499)
    {
        a = 0;
        b = 0;
               fout << "start of while loop \n";

            while ((newimg.at<Vec3b>(b,a) == Vec3b(0,0,0)))    
            {
                fout << "inside the while loop \n"
                a = rand() % imgwidth;
                b = rand() % imgheight;

            }
            fout << "outside the while loop \n"; 
            fout << a;
            fout << " ";
            fout << b;
            fout << " ";
            i++;

        }

        j++;
        fout << "\n";

    }


}
Keymaker
  • 137
  • 14
  • 1
    What you want to achieve exactly? do "imgwidth = newimg.cols; imgheight = newimg.rows;" and you should be fine. Also read some C++ tutorial and learn why you don't need pointers, new, "->" here – Miki Oct 28 '15 at 01:59
  • as @Miki stated, width should correspond to the number of cols and height should be the number of rows. Maybe you got confused with x/y ordering and matrix access. Look at http://stackoverflow.com/questions/25642532/opencv-pointx-y-represent-column-row-or-row-column/25644503#25644503 for a possible explanation. – Micka Oct 28 '15 at 10:02
  • I tried you suggestions, but the code is still not working. I have modified my question and included debug statements printed to a .txt file. – Keymaker Oct 28 '15 at 13:04
  • What you want to achieve exactly? Two while loops on a magic number are not the best option :D – Miki Oct 28 '15 at 14:22
  • @Miki I am trying to build a random feature set of points which are white from a filtered image. That requires me to randomly generate points and check if they are white or not...... – Keymaker Oct 28 '15 at 15:25
  • posted an answer, is that what you want to do? – Miki Oct 28 '15 at 16:02

2 Answers2

1

I am trying to build a random feature set of points which are white from a filtered image. That requires me to randomly generate points and check if they are white or not

You don't need to generate random points in the correct image range, and check if a pixel is white or not in the original image.

You can:

  • get all white pixels in mask, with findNonZero
  • random shuffle these points, with std::random_shuffle
  • keep first N shuffled points

Masked image:

enter image description here

Random sampled N white points in mask:

enter image description here

Code:

#include <opencv2\opencv.hpp>
#include <vector>
#include <algorithm>
using namespace cv;
using namespace std;

int main()
{
    Mat3b img = imread("path_to_image");

    Mat3b hsv;
    cvtColor(img, hsv, COLOR_BGR2HSV);

    Mat1b mask;
    inRange(hsv, Scalar(0, 30, 60), Scalar(20, 150, 255), mask);

    // Get all white points in mask
    vector<Point> pts;
    findNonZero(mask, pts);

    int N = 1000; // number of random points to keep
    N = min(N, int(pts.size())); // not more than the actual white pixels

    // Random shuffle of white points
    random_shuffle(pts.begin(), pts.end());

    // Random subset of N white points in mask
    vector<Point> my_random_points(pts.begin(), pts.begin() + N);

    // Create a black image
    Mat1b random_in_mask(mask.rows, mask.cols, uchar(0));

    // Set selected random points to white
    for (const Point& pt : my_random_points)
    {
        random_in_mask(pt) = uchar(255);
    }

    imshow("Mask", mask);
    imshow("Random in Mask", random_in_mask);

    waitKey();

    return 0;
}
Miki
  • 40,887
  • 13
  • 123
  • 202
  • thnks fr ur sln.this helped me.but I really want to understand what is the fault in the way I am doing it.my image width is(number of columns) 1728 and my image height (number of rows is) 3072, but my image.at pixel access breaks at image.at(404, 1173) , both of which are in the range of image width and and image height. Its strange but when i access image.at(1173 ,404) it gives me result. (ideally it should give result for both image.at(1173 ,404) and image.at(404, 1173) ) .....as 1173 and 404 are both in range of 1728 and 3072......do you know about this??? – Keymaker Oct 29 '15 at 13:06
  • `newimg` is a CV_8UC1, you need to access it using `newimg.at(rows, cols)`. you can check if the value is zero simply using: `if(!newimg.at(rows, cols)){...}` – Miki Oct 29 '15 at 13:10
  • I am trying to upvote and it is saying smthng about reputation and 15 points.............. :D..... :) – Keymaker Oct 29 '15 at 13:55
  • @AsimUnmesh Don't worry, glad you make it work. I hope that my answer at least shows the correct procedure to get to your result. – Miki Oct 29 '15 at 13:57
0

EDIT: InRange leaves newimg with type uchar or CV_8U, so change the condition to:

newimg.at<uchar>(a,b) == (uchar) 0

will solve the problem. Updated my answer according to comments below.

According to the this, the row is the dimension 0, which is the width. In at<>(i,j), i is along the dimension 0 j is along the 1. Your image is probably rectangular, so you second pair of rand()-s result cause bad a,b-s.

EDIT: In your code you have

while ((newimg.at<Vec3b>(b,a) == Vec3b(0,0,0)))    
{
     fout << "inside the while loop \n"
     a = rand() % imgwidth;
     b = rand() % imgheight;
}

Change this to

while ((newimg.at<Vec3b>(b,a) == Vec3b(0,0,0)))    
{
     fout << "inside the while loop \n"
     a = rand() % imgheight;
     b = rand() % imgwidth;
}

Or

while ((newimg.at<Vec3b>(a,b) == Vec3b(0,0,0)))    
{
     fout << "inside the while loop \n"
     a = rand() % imgwidth;
     b = rand() % imgheight;
}

I am saying this should work, not that it would.

EDIT #2: Explanation

You have a picture which looks like this for example:

-----------
|         |
|         |
|         |
|         |
|         |
|         |
-----------

But a and be with the at<>(b,a) usage order creates a different rectangle, so:

------------------
|         |      |
|         |   2  |
|     1   |      |
|---------|-------
|         |
|         |
-----------

Your first pair of random numbers have been generated to the (1) position, while the second pair is not on the image. You did not use srand(time(NULL)); so your random numbers are the same at each run.

  • Sorry, I couldn't properly understand why the second pair of rand() cause bad a,b. I have edited the question too after trying the above suggestions and I have included the output of a .txt file in which i have printed the debug statements. Maybe those can help you see my problem better. – Keymaker Oct 28 '15 at 13:06
  • @AsimUnmesh I have updated my answer to include the edit needed in my code. – Csaba Bálint Oct 28 '15 at 15:21
  • @AsimUnmesh I see, i looked into it, in core.hpp, look at the comment on line 1259 (above inRange): `@param dst output array of the same size as src and CV_8U type. ` So newtype is not a Vec3b, it is either 0b00000000 or 0b11111111, no channels. – Csaba Bálint Oct 28 '15 at 15:39
  • @AsimUnmesh Sorry for editing my comment a lot. The indexing boundaries might still be an issue though. – Csaba Bálint Oct 28 '15 at 15:43
  • So I recommend trying `newimg.at(a,b) == (uchar) 0` for comparison. If it works I update my answer. – Csaba Bálint Oct 28 '15 at 15:46