Opencv: Find All Non-Zero Coordinates of a Binary Mat Image

OpenCV: Find all non-zero coordinates of a binary Mat image

Here is an explanation for how findNonZero() saves non-zero elements. The following codes should be useful to access non-zero coordinates of your binary image. Method 1 used findNonZero() in OpenCV, and Method 2 checked every pixels to find the non-zero (positive) ones.

Method 1:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;

int main(int argc, char** argv) {
Mat img = imread("binary image");
Mat nonZeroCoordinates;
findNonZero(img, nonZeroCoordinates);
for (int i = 0; i < nonZeroCoordinates.total(); i++ ) {
cout << "Zero#" << i << ": " << nonZeroCoordinates.at<Point>(i).x << ", " << nonZeroCoordinates.at<Point>(i).y << endl;
}
return 0;
}

Method 2:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;

int main(int argc, char** argv) {
Mat img = imread("binary image");
for (int i = 0; i < img.cols; i++ ) {
for (int j = 0; j < img.rows; j++) {
if (img.at<uchar>(j, i) > 0) {
cout << i << ", " << j << endl; // Do your operations
}
}
}
return 0;
}

OpenCV - locations of all non-zero pixels in binary image

As suggested by @AbidRahmanK, there is a function cv::findNonZero in OpenCV version 2.4.4. Usage:

cv::Mat binaryImage; // input, binary image
cv::Mat locations; // output, locations of non-zero pixels
cv::findNonZero(binaryImage, locations);

It does the job. This function was introduced in OpenCV version 2.4.4 (for example, it is not available in the version 2.4.2). Also, as of now findNonZero is not in the documentation for some reason.

How to find nonzero pixels in specific territory in Mat

Hi Here is a sample implementation! Please use this!

void findNonZero( InputArray _src, InputArray _Mask, OutputArray _idx )
{
Mat src = _src.getMat();
Mat msk = _Mask.getMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( src.size() == msk.size());

int n = countNonZero(src);
if( n == 0 )
{
_idx.release();
return;
}
if( _idx.kind() == _InputArray::MAT && !_idx.getMatRef().isContinuous() )
_idx.release();
_idx.create(n, 1, CV_32SC2);
Mat idx = _idx.getMat();
CV_Assert(idx.isContinuous());
Point* idx_ptr = idx.ptr<Point>();

for( int i = 0; i < src.rows; i++ )
{
const uchar* bin_ptr = src.ptr(i);
const uchar* msk_ptr = msk .ptr(i);
for( int j = 0; j < src.cols; j++ )
if( bin_ptr[j] && msk_ptr[j])
*idx_ptr++ = Point(j, i);
}
}

int _tmain(int argc, _TCHAR* argv[])
{
string sFileNameEx="F:\\Balaji\\Image Samples\\Test.jpg";
size_t lastindex = sFileNameEx.find_last_of(".");
String sFileName = sFileNameEx.substr(0, lastindex);
bool bSaveImages=true;

Mat mSrc_Gray,mSrc_Mask,mResult_Bgr;

mSrc_Gray= imread(sFileNameEx,0);
mSrc_Mask= Mat(mSrc_Gray.size(),CV_8UC1,Scalar(0));
cvtColor(mSrc_Gray,mResult_Bgr,COLOR_GRAY2BGR);

if(mSrc_Gray.empty())
{
cout<<"[Error]! Invalid Input Image";
return 0;
}

threshold(mSrc_Gray,mSrc_Gray,10,255,THRESH_BINARY);
imshow("mSrc_Gray",mSrc_Gray);

Sample Image

    vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Find contours
findContours( mSrc_Gray.clone(), contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0) );

for( size_t i = 0; i < contours.size(); i++ )
{
if(contourArea(contours[i])>500)
{
drawContours(mSrc_Mask,contours,i,Scalar(255),-1);
}
}

//May be further Filtering like erode needed?
imshow("mSrc_Mask",mSrc_Mask);

Sample Image

    vector<Point> locations;   // output, locations of non-zero pixels

findNonZero(mSrc_Gray,mSrc_Mask,locations);

for( size_t i = 0; i < locations.size(); i++ )
{
circle(mResult_Bgr,locations[i],1,Scalar(0,255,0),1);
}
imshow("mResult_Bgr",mResult_Bgr);

Sample Image

    waitKey(0);
return 0;
}

How to access findNonZero coordinates stored in Mat C++

I expect the following to work:

Point loc_i = NonZero_Locations.at<Point>(i);

How to count zero pixels between consecutive non-zero ones in OpenCV?

I think you should fit a line over the endpoints and count the zero pixels under it. OpenCV has a LineIterator class which you can make a 8-connected or 4-connected line from (30, 20) to (30, 23) and check the values.

Copy only row indices of Mat from findNonZero function in C++ OpenCV

MATLAB's find determines the column-major indices of where values are nonzero in the input matrix. This is true if you specify the single output version of it. If you provide two output variables, that generates both the row and column locations of the nonzero values in the input. In your example you have provided the single output version of find so I will be working with this.

OpenCV's cv::Mat lays out the image in row-major. I'm assuming you would like the row-major indices. If so, since cv::findNonZero outputs both the row and column coordinates, you must loop through the output coordinates yourself and create the row-major indices. You shouldn't be afraid of using loops here. In fact, for loops over cv::Mats are optimised for quick access. Therefore:

Mat2i idx;
Mat1d A; // Define somewhere else
double s; // Define somewhere else

findNonZero(A > s, idx);
B = Mat1i::zeros(idx.total());
for (int i = 0; i < idx.total(); ++i) {
B.at<int>(i) = idx.at<Point>(i).y * A.cols + idx.at<Point>(i).x;
}

B will contain the row-major indices in a cv::Mat1i. If I have misunderstood your inquiry and simply want the row locations of the nonzero values, then it's just:

Mat2i idx;
Mat1d A; // Define somewhere else
double s; // Define somewhere else

findNonZero(A > s, idx);
B = Mat1i::zeros(idx.total());
for (int i = 0; i < idx.total(); ++i) {
B.at<int>(i) = idx.at<Point>(i).y;
}

Remember you are only iterating over the nonzero values, so the worst case complexity is to iterate over the locations that are nonzero.

Get coordinates of white pixels (OpenCV)

there is a built-in function to do that cv::findNonZero

Returns the list of locations of non-zero pixels.

Given a binary matrix (likely returned from an operation such as cv::threshold(), cv::compare(), >, ==, etc) returns all of the non-zero indices as a cv::Mat or std::vector<cv::Point>

For example:

cv::Mat binaryImage; // input, binary image
cv::Mat locations; // output, locations of non-zero pixels
cv::findNonZero(binaryImage, locations);
// access pixel coordinates
Point pnt = locations.at<Point>(i);

or

cv::Mat binaryImage; // input, binary image
vector<Point> locations; // output, locations of non-zero pixels
cv::findNonZero(binaryImage, locations);
// access pixel coordinates
Point pnt = locations[i];


Related Topics



Leave a reply



Submit