I am using the OpenCV C++ API (version 4.7.0). I have an application where I need to determine the centroid of a laser spot through a camera feed, and to do that I am attempting to use the connectedComponentsWithStats()
function.
In my current setup, the image data is defined in a text file as a 2D array. This data is of a binary image, which is expected by connectedCoponentsWithStats()
. The size of the image is 625X889. Here is what the binary image looks like:
This is the result of a binary thresholding operation.
Here is my C++ code for computing the centroids of the connected components:
/* Grouping and centroiding implementation using OpenCV's
* ConnectedComponentsWithStats().
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
uint32_t ROWS=625;
uint32_t COLS=889;
uint8_t image_array[ROWS][COLS];
uint8_t *image_data = new uint8_t[ROWS * COLS];
int i;
int j;
//Read data from file and save into image_array[][].
ifstream fp("./data/binary_image/binary_image1.txt");
if (! fp)
{
cout << "Error opening file" << endl;
return 1;
}
for (i=0; i<ROWS; i++)
{
for (j=0; j<COLS; j++)
{
fp >> image_array[i][j];
if (! fp)
{
cout << "Error reading file for element " << i << "," << j << endl;
return 1;
}
}
}
//Copy data into a 1D array called image_data.
for (i=0; i<ROWS; i++)
{
for (j=0; j<COLS; j++)
{
if (image_array[i][j] == 1)
{
image_array[i][j] = 255;
}
image_data[i * COLS + j] = image_array[i][j];
}
}
//Create image object.
cv::Mat image(ROWS, COLS, CV_8U, image_data);
//Create output objects.
cv::Mat labels, stats, centroids;
//Pass image to connectedComponentsWithStats() function.
int num_components = cv::connectedComponentsWithStats(image, labels, stats, centroids);
//Print out the centroids
for (i=0; i<num_components; i++)
{
cout << "Centroid "<< i << ": (" << centroids.at<double>(i, 0) << ", " << centroids.at<double>(i,1) << ")" << endl;
}
return 0;
}
Not that is it important, but this is how I compiled the code:
g++ `pkg-config --cflags opencv4` -c opencv_grouping.cpp
g++ opencv_grouping.o `pkg-config --libs opencv4` -o opencv_test
This is the output after running ./opencv_test
:
Centroid 0: (nan, nan)
Centroid 1: (444, 312)
I am not really sure why I am getting the nan
result, but I suppose this means that the area of that connected component is 0? As for the (444, 312)
result, that just corresponds (roughly) to the center of a 625X889 grid, which is the size of the inputted image. So it essentially just computed the center of that grid. I tried with several other input images of the same size that were generated using different thresholds (so the spot size varried), and it yielded exactly the same result.
Does anyone have any insight/suggestions as to what might be going on here? Does OpenCV provide other functions that can be used to compute the centroid of the spot?
--Update--
I think that I found out where the problem is coming from. Something very strange is happening when I am reading in the data from the text file. It's not reading the data correctly at all. It gets to row 440 and then the rest of the data is either 0 or some garbage value (like a really large negative number for example). I am not sure why this is happening. In addition to declaring image_array
as uint8_t image_array[ROWS][COLS]
, I have also tried allocating memory for it with new
:
uint8_t **image_array = new uint8_t*[ROWS];
for (i=0; i<ROWS; i++)
{
image_array[i] = new uint8_t[COLS];
}
Both of these run into the same problem. As a sanity check, I created a smaller (19X20) array to test with. It looks like this in a text file:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 255 255 255 0 0 0 0 0 0 255 255 255 255 255 0 0 0
0 0 0 255 255 255 0 0 0 0 0 0 0 255 255 255 0 0 0 0
0 0 255 255 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0
0 0 0 255 255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 0
0 0 0 0 255 255 255 255 255 0 0 255 255 255 0 0 0 0 0 0
0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 0
0 0 0 0 0 0 0 255 255 255 255 255 255 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
I run this through the code my code (with ROWS=19
and COLS=20
) and it actually gives a reasonable output for the centroids:
Centroid 0: (9.63497, 9.22086)
Centroid 1: (3.8, 3.1)
Centroid 2: (14, 2.55556)
Centroid 3: (8.71429, 10.2857)
So the issue is that the larger array is not getting read from the text file correctly. Any suggestions?