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);
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);
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);
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::Mat
s 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
C++11 Rvalue Reference Calling Copy Constructor Too
Is a Linked-List Implementation Without Using Pointers Possible or Not
Why Does the Main Function Work with No Return Value
Convert a Static Library to a Shared Library (Create Libsome.So from Libsome.A): Where's My Symbols
Cin.Getline() Is Skipping an Input in C++
Using Std::Map<K,V> Where V Has No Usable Default Constructor
Why Is Volatile Deprecated in C++20
Error: 'Int32_Max' Was Not Declared in This Scope
When Should Functions Be Member Functions
What Does the Vertical Pipe ( | ) Mean in C++
C++: Fastest Method to Check If All Array Elements Are Equal
How to Enable_Shared_From_This of Both Parent and Derived
Why Isn't Rvo Applied to Base Class Subobject Initialization