OpenCV 3 C++ Mat 使用指针获取随机
OpenCV 3 C++ Mat fetching with pointer goes random
我是 OpenCV 的新手,我现在使用的是带有 C++ 实现的 3.4.1 版。我还在探索中,所以这个问题不是针对某个项目的,而是更多的"try to understand how it works"。请以同样的想法考虑,我知道我以某种方式 "reinventing the will" 使用这段代码,但我写这个例子是为了理解 "HOW IT WORKS".
想法是:
- 读取 RGB 图像
- 将其设为二进制
- 查找连通区域
- 给每个区域涂上不同的颜色
例如,我使用保存为 BMP 的 5x5 像素 RGB 图像。该图像是一个白色框,其轮廓周围有黑色像素。
直到我得到名为 Mat::Labels 的 ConnectedComponents 矩阵,一切顺利。如果我打印矩阵,我会看到我所期望的:
11111
10001
10001
10001
11111
请记住,我已经反转了阈值,因此在边缘获得 1 是正确的...
然后我创建了一个 Mat,其大小与 Mat::Labels 相同,但有 3 个通道以使用 RGB 为其着色。这被命名为 Mat::ColoredLabels。
下一步是实例化一个贯穿 Mat::Labels 的指针,对于 Mat::Labels 中值为 1 的每个位置,用颜色填充相应的 Mat:.ColoredLabels 位置。
这里出了点问题!指针没有像我期望的那样逐行获取 Mat::Labels 行,而是遵循其他顺序。
问题:
- 我做错了什么还是"obvious"指针获取遵循某种"umpredictable"顺序?
- 如何根据另一个矩阵 (Mat::Labels) 的值设置矩阵 (Mat::ColoredLabels) 的值?
.
#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;
}
您使用了带有 CV_16U 参数的 connectedComponents 函数。这意味着图像的单个元素将由 16 位组成(因此为“16”),您必须将它们解释为无符号整数(因此为 'U')。由于 ptr
returns 是一个指针,您必须取消引用它才能获取值。
因此您应该通过以下方式访问标签图像元素:
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
我是 OpenCV 的新手,我现在使用的是带有 C++ 实现的 3.4.1 版。我还在探索中,所以这个问题不是针对某个项目的,而是更多的"try to understand how it works"。请以同样的想法考虑,我知道我以某种方式 "reinventing the will" 使用这段代码,但我写这个例子是为了理解 "HOW IT WORKS".
想法是:
- 读取 RGB 图像
- 将其设为二进制
- 查找连通区域
- 给每个区域涂上不同的颜色
例如,我使用保存为 BMP 的 5x5 像素 RGB 图像。该图像是一个白色框,其轮廓周围有黑色像素。
直到我得到名为 Mat::Labels 的 ConnectedComponents 矩阵,一切顺利。如果我打印矩阵,我会看到我所期望的:
11111
10001
10001
10001
11111
请记住,我已经反转了阈值,因此在边缘获得 1 是正确的...
然后我创建了一个 Mat,其大小与 Mat::Labels 相同,但有 3 个通道以使用 RGB 为其着色。这被命名为 Mat::ColoredLabels。 下一步是实例化一个贯穿 Mat::Labels 的指针,对于 Mat::Labels 中值为 1 的每个位置,用颜色填充相应的 Mat:.ColoredLabels 位置。
这里出了点问题!指针没有像我期望的那样逐行获取 Mat::Labels 行,而是遵循其他顺序。
问题:
- 我做错了什么还是"obvious"指针获取遵循某种"umpredictable"顺序?
- 如何根据另一个矩阵 (Mat::Labels) 的值设置矩阵 (Mat::ColoredLabels) 的值?
.
#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;
}
您使用了带有 CV_16U 参数的 connectedComponents 函数。这意味着图像的单个元素将由 16 位组成(因此为“16”),您必须将它们解释为无符号整数(因此为 'U')。由于 ptr
returns 是一个指针,您必须取消引用它才能获取值。
因此您应该通过以下方式访问标签图像元素:
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