Abhishek Thakur
Abhishek Thakur

Reputation: 17025

accessing image pixels as float array

I want to access image pixels as float array in opencv. Ive done the following:

Mat input = imread("Lena.jpg",CV_LOAD_IMAGE_GRAYSCALE);
int height = input.rows;
int width = input.cols;

Mat out;
input.convertTo(input, CV_32FC1);
copyMakeBorder(input, input, 3, 3, 3, 3, 0);

out = Mat(height, width, input.type());

float *outdata = (float*)out.data;
float *indata = (float*)input.data;

for(int j = 0; j < height; j++){
    for(int i =0; i < width; i++){
        outdata[j*width + i] = indata[(j* width + i)];
    }
}


normalize(out, out,0,255,NORM_MINMAX,CV_8UC1);

imshow("output", out);
waitKey();

This should return the original image in "out", however, I'm getting some weird image. Can anyone explain whats wrong with the code. I think i need to use some step size (widthStep). Thanks.

Upvotes: 2

Views: 2031

Answers (4)

Hammer
Hammer

Reputation: 10329

the line

    copyMakeBorder(input, input, 3, 3, 3, 3, 0);

changes the dimensions of input, it adds 6 rows and 6 columns to the image. That means your height and width variables are holding the wrong values when you define out and try to loop over the values on input.

if you change the order to

copyMakeBorder(input, input, 3, 3, 3, 3, 0);

int height = input.rows;
int width = input.cols;

it should work fine.

Upvotes: 1

rotating_image
rotating_image

Reputation: 3086

You can try this loop...

    for(int row=0;row<height;row++)
    {
        for(int col=0;col<width;col++)
        {
            float float_data = input.at<float>(row,col);
            // do some processing with value of float_data
            out.at<float>(row,col) = float_data;
        }
    }

Is there a need to cast the uchar pointers of input and out Mats to float pointers?

Upvotes: 1

s.bandara
s.bandara

Reputation: 5664

To really make it apparent what the problem is, imagine a 16 by 16 image. Now think of pixel number 17 in the linear representation.

17 is a prime number. There is no j*i that will index your source image at pixel 17 if the row or column width is 16. Thus elements like 17, 19, 23 and so on will be uninitialized or at best 0, resulting in a "weird" output.

How about pixel 8 in the linear representation? that one in contrast will get hit by your loop four times, i.e. by 1x8, 2x4, 4x2, and 8x1!

The indexing @NateKohl presents in his answer will fix it since he multiplies a row position by the length of the row and then simply walks along the columns.

Upvotes: 1

Nate Kohl
Nate Kohl

Reputation: 35944

Some ideas:


Something like outdata[j*width + i] is a more standard pattern for this sort of thing.


According to the opencv documentation, there is a templated Mat::at(int y, int x) method that allows you to access individual elements of a matrix.

float f = input.at<float>(0, 0); 

Note that this requires that your underlying matrix type is float -- it won't do a conversion for you.


Alternatively, you could access the data row-by-row, as in this example that sums up the positive elements of a matrix M of type double:

double sum=0;
for(int i = 0; i < M.rows; i++)
{
    const double* Mi = M.ptr<double>(i);
    for(int j = 0; j < M.cols; j++)
        sum += std::max(Mi[j], 0.);
}

If none of these work, I'd suggest creating a small matrix with known values (e.g. a 2x2 matrix with 1 black pixel and 3 white pixels) and use that to help debug your code.

Upvotes: 1

Related Questions