Я довольно новичок в OpenCV, и теперь я использую версию 3.4.1 с реализацией C ++. Я все еще изучаю, поэтому этот вопрос не является специфическим для проекта, а скорее «попытка понять, как он работает». Пожалуйста, учтите, с той же идеей, что я знаю, что я каким-то образом «заново изобретаю волю» с помощью этого кода, но я написал этот пример, чтобы понять, «КАК ЭТО РАБОТАЕТ».
Идея заключается в следующем:
В качестве примера я использую изображение RGB 5×5 пикселей, сохраненное как BMP. Изображение представляет собой белый прямоугольник с черными пикселями по всему контуру.
До того момента, когда я получаю матрицу ConnectedComponents с именем Mat :: Labels, все прошло нормально. Если я распечатаю Матрицу, я вижу именно то, что ожидаю:
11111
10001
10001
10001
11111
Помните, что я перевернул порог, поэтому правильно получить 1 по краям …
Затем я создаю Mat с тем же размером Mat :: Labels, но с 3 каналами, чтобы раскрасить его RGB. Это называется Mat :: ColoredLabels.
Следующим шагом является создание указателя, который проходит через Mat :: Labels и для каждой позиции в Mat :: Labels, где значение равно 1, заполните соответствующую позицию Mat: .ColoredLabels цветом.
ЗДЕСЬ ВЕЩИ ПОЛУЧИЛИ ОЧЕНЬ НЕПРАВИЛЬНО! Указатель не извлекает строку байта строки Mat :: Labels, как я ожидал, но следует в другом порядке.
Вопросы:
.
#include "opencv2\highgui.hpp"#include "opencv2\opencv.hpp"#include <stdio.h>
using namespace cv;
int main(int argc, char *argv[]) {
char* FilePath = "";
Mat Img;
Mat ImgGray;
Mat ImgBinary;
Mat Labels;
uchar *P;
uchar *CP;
// Image acquisition
if (argc < 2) {
printf("Missing argument");
return -1;
}
FilePath = argv[1];
Img = imread(FilePath, CV_LOAD_IMAGE_COLOR);
if (Img.empty()) {
printf("Invalid image");
return -1;
}
// Convert to Gray...I know I could convert it right away while loading....
cvtColor(Img, ImgGray, CV_RGB2GRAY);
// Threshold (inverted) to obtain black background and white blobs-> it works
threshold(ImgGray, ImgBinary, 170, 255, CV_THRESH_BINARY_INV);
// Find Connected Components and put the 1/0 result in Mat::Labels
int BlobsNum = connectedComponents(ImgBinary, Labels, 8, CV_16U);
// Just to see what comes out with a 5x5 image. I get:
// 11111
// 10001
// 10001
// 10001
// 11111
std::cout << Labels << "\n";
// Prepare to fetch the Mat(s) with pointer to be fast
int nRows = Labels.rows;
int nCols = Labels.cols * Labels.channels();
if (Labels.isContinuous()) {
nCols *= nRows;
nRows = 1;
}
// Prepare a Mat as big as LAbels but with 3 channels to color different blobs
Mat ColoredLabels(Img.rows, Img.cols, CV_8UC3, cv::Scalar(127, 127, 127));
int ColoredLabelsNumChannels = ColoredLabels.channels();
// Fetch Mat::Labels and Mat::ColoredLabes with the same for cycle...
for (int i = 0; i < nRows; i++) {
// !!! HERE SOMETHING GOES WRONG !!!!
P = Labels.ptr<uchar>(i);
CP = ColoredLabels.ptr<uchar>(i);
for (int j = 0; j < nCols; j++) {
// The coloring operation does not work
if (P[j] > 0) {
CP[j*ColoredLabelsNumChannels] = 0;
CP[j*ColoredLabelsNumChannels + 1] = 0;
CP[j*ColoredLabelsNumChannels + 2] = 255;
}
}
}
std::cout << "\n" << ColoredLabels << "\n";
namedWindow("ColoredLabels", CV_WINDOW_NORMAL);
imshow("ColoredLabels", ColoredLabels);
waitKey(0);
printf("Execution completed succesfully");
return 0;
}
Ты использовал connectedComponents функция с параметром CV_16U. Это означает, что один элемент изображения будет состоять из 16 бит (следовательно, «16»), и вы должны интерпретировать их как целое число без знака (следовательно, «U»). И с тех пор ptr
возвращает указатель, вы должны разыменовать его, чтобы получить значение.
Поэтому вы должны получить доступ к элементам изображения метки следующим образом:
unsigned short val = *Labels.ptr<unsigned short>(i) // or uint16_t
unsigned short val = Labels.at<unsigned short>.at(y, x);
Что касается вашего второго вопроса, это так просто, но, конечно, вы должны понимать, какие типы приведений приводят к потере точности или переполнению, а какие нет.
mat0.at<int>(y, x) = mat1.at<int>(y, x); // both matrices have CV_32S types
mat2.at<int>(y, x) = mat3.at<char>(y,x); // CV_32S and CV_8S
// Implicit cast occurs. Possible information loss: assigning 32-bit integer values to 8-bit ints
// mat4.at<unsigned char>(y, x) = mat5.at<unsigned int>(y, x); // CV_8U and CV_32U
Других решений пока нет …