[英]after merging and extracting the BGR channel, compilation is successful,but there is a run-time error: ILLEGAL OPERATION
我正在尝试从我已经拥有的3个不同的CV_8UC1图像创建1个CV_8UC3图像,即,我正在尝试将已经拥有的不同单通道图像分配到单个1多维图像中。 下面的代码可能可以完美地直接用于3通道图像,但是如果进行合并和提取,则会出现Runtime错误 。 非法操作
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<vector>
typedef cv::Vec3b Pixel; // correct
struct Operator {
void operator ()(cv::Vec3b &pixel, const int * position) const
{
pixel[2]*=0.5;
}
};
int main(int argc, char** argv )
{
cv::VideoCapture cap(0);
if(!cap.isOpened())
return -1;
cv::Mat frame1,frame2,for_each,cblue, cgreen, cred;
std::vector<cv::Mat> channels { cblue, cgreen, cred};
for(;;)
{
cap >> frame1;
cvtColor(frame1, frame1, cv::COLOR_BGR2GRAY);
frame1.convertTo(frame2,CV_8U);
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
cv::merge(channels, for_each);
double t1 = (double)cv::getTickCount();
for_each.forEach<Pixel>(Operator());
t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
std::cout<< "Parallel TEST time " << t1 << std::endl;
cv::extractChannel (for_each, cblue, 0 );
cv::imshow("cropped_BGR",frame1);
cv::imshow("mod_BLUE",cblue);
if (cv::waitKey(30) == 27)
{
std::cout << "esc key is pressed by user" <<std::endl;
break;
}
}
return 0;
}
我不知道从哪里来这个错误,TIA会非常感谢您的帮助。
执行此操作时:
cv::Mat frame1,frame2,for_each,cblue, cgreen, cred;
std::vector<cv::Mat> channels { cblue, cgreen, cred};
channels
将具有cv::Mat
cblue
, cgreen
和cred
的浅表副本。 这意味着它们都将具有相同的标头和指向相同位置的数据指针。
然后,您执行以下操作:
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
它将frame2的深层副本复制到每个cv :: Mat中。 copyTo
的文档说:
m –目标矩阵。 如果在操作之前它的大小或类型不正确,则会对其进行重新分配。
这意味着,指向数据的指针将发生变化,但是不会更改为向量内的cv :: Mat,它们仍将指向nullptr
而cblue
, cgreen
和cred
将指向另一个位置。
我用以下代码进行了测试:
cv::Mat frame(500, 500, CV_8UC3, cv::Scalar::all(111));
cv::Mat frame1, frame2, cblue, cgreen, cred;
std::vector<cv::Mat> channels{ cblue, cgreen, cred };
// at this point all data members of mat will point to nullptr except frame
cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY);
frame.convertTo(frame2, CV_8U);
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
// at this point all point to another place except the ones inside the vector
1)创建引用而不是副本:
cv::Mat frame1, frame2;
std::vector<cv::Mat> channels(3);
cv::Mat& cblue = channels[0], &cgreen=channels[1], &cred=channels[2];
2)直接使用通道,而不使用其他变量
frame2.copyTo(channels[0]);
frame2.copyTo(channels[1]);
frame2.copyTo(channels[2]);
3)在循环内创建向量
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
std::vector<cv::Mat> channels { cblue, cgreen, cred};
cv::merge(channels, for_each);
4)您的代码等效于:
cvtColor(frame1, frame1, cv::COLOR_BGR2GRAY);
cvtColor(frame1, for_each, cv::COLOR_GRAY2BGR);
这将创建一个3通道的灰度值图像,基本上是每个通道中的灰度垫的副本...
5)还有一件事:
frame1.convertTo(frame2,CV_8U);
这不是必需的,因为它已经是CV_8U
垫,因为上一条指令将其转换为CV_8U
灰度,然后您甚至可以在其中创建向量而无需进行深拷贝(它将深拷贝到for_each)。
std::vector<cv::Mat> channels { frame1, frame1, frame1};
cv::merge(channels, for_each);
还有另一件事,与错误无关:
cv::extractChannel (for_each, cblue, 0 );
cv::imshow("cropped_BGR",frame1);
cv::imshow("mod_BLUE",cblue);
将显示完全相同的图像:)或至少应显示。
确实,最好的答复之一。 非常感谢你 !!!
sol3 :效果很好
double t1 = (double)cv::getTickCount();
std::vector<cv::Mat> channels { cblue, cgreen, cred};
cv::merge(channels, for_each);
for_each.forEach<Pixel>(Operator());
cv::extractChannel (for_each, cblue, 2 );
t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
std::cout<< "Parallel TEST time " << t1 << std::endl;
sol1 :但是它仍然给我
错误:“ class std :: vector”没有名为“ forEach”的成员。forEach(Operator()); ^ ~~~~~~ 16_vector_foreach_changedmaincode.cpp:54:31:错误:令牌通道之前的预期主表达式。forEach(Operator());
我的意图是
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
double t1 = (double)cv::getTickCount();
//std::vector<cv::Mat> channels { cblue, cgreen, cred};
std::vector<cv::Mat> channels(3);
cv::Mat& cblue = channels[0], &cgreen=channels[1], &cred=channels[2];
//cv::merge(channels, for_each);
channels.forEach<Pixel>(Operator());
cv::extractChannel (channels, cblue, 2 );
t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
std::cout<< "Parallel TEST time " << t1 << std::endl;
我还必须在这里使用合并运算符吗? @ api55
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.