Home > Blockchain >  How to get all pixels in mask in C
How to get all pixels in mask in C

Time:11-23

In python, we can use such code to fetch all pixels under mask:

src_img = cv2.imread("xxx")
mask = src_img > 50
fetch = src_img[mask]

what we get is a ndarray including all pixels matching condition mask. How to implement the same function using C opencv ?

I've found that copyTo can select pixels under specified mask, but it can only copy those pixels to another Mat instead of what python did.

CodePudding user response:

This is not that straightforward in C (as expected). That operation breaks down in further, smaller operations. One way to achieve a std::vector with the same pixel values above your threshold is this, I'm using this test image:

// Read the input image:
std::string imageName = "D://opencvImages//grayDog.png";
cv::Mat inputImage =  cv::imread( imageName );

// Convert BGR to Gray:
cv::Mat grayImage;
cv::cvtColor( inputImage, grayImage, cv::COLOR_RGB2GRAY );

cv::Mat mask;
int thresholdValue = 50;
cv::threshold( grayImage, mask, thresholdValue, 255, cv::THRESH_BINARY );

The above bit just creates a cv::Mat where each pixel above the threshold is drawn with a value of 255, 0 otherwise. It is (one possible) equivalent of mask = src_img > 50. Now, let's mask the original grayscale image with this mask. Think about an element-wise multiplication between the two cv::Mats. One possible way is this:

// Create grayscale mask:
cv::Mat output;
grayImage.copyTo( output, mask );

Now we have the original pixel values and everything else is zero. Convenient, because we can find now the locations of the non-zero pixels:

// Locate the non-zero pixel values:
std::vector< cv::Point > pixelLocations;
cv::findNonZero( output, pixelLocations );

Alright, we have a std::vector of cv::Points that locate each non-zero pixel. We can use this info to index the original grayscale pixels in the original matrix:

// Extract each pixel value using its location:
std::vector< int > pixelValues;
int totalPoints = (int)pixelLocations.size();

for( int i = 0; i < totalPoints; i   ){
    // Get pixel location:
    cv::Point currentPoint = pixelLocations[i];

    // Get pixel value:
    int currentPixel = (int)grayImage.at<uchar>( currentPoint );
    pixelValues.push_back( currentPixel );

    // Print info:
    std::cout<<"i: "<<i<<" currentPoint: "<<currentPoint<<" pixelValue: "<<currentPixel<<std::endl;
}

You end up with pixelValues, which is a std::vector containing a list of all the pixels that are above your threshold.

CodePudding user response:

Why do you hate writing loop?

I think this is the easiest way:

cv::Mat Img = ... //Where, this Img is 8UC1

// * In this sample, extract the pixel positions
std::vector< cv::Point > ResultData;

const unsigned char Thresh = 50;
for( int y=0; y<Img.rows;   y )
{
    const unsigned char *p = Img.ptr<unsigned char>(y);
    for( int x=0; x<Img.cols;   x,   p )
    {
        if( *p > Thresh )
        {//Here, pick up this pixel's info you want.
            ResultData.emplace_back( x,y );
        }
    }
}
  • Related