after merging and extracting the BGR channel, compilation is successful,but there is a run-time error: ILLEGAL OPERATION
after merging and extracting the BGR channel, compilation is successful,but there is a run-time error: ILLEGAL OPERATION
我 trying 从我已有的 3 个不同 CV_8UC1 图像创建 1 CV_8UC3 图像,即我正在尝试分配我已有的不同单通道图像成一个单一的 1 多维图像。
下面的代码可能直接与 3 通道图像一起完美运行,但如果合并和提取它会出现运行时错误。
非法操作
#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
的浅表副本。这意味着,它们都将具有相同的 headers 和指向同一位置的数据指针。
然后你做:
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
对每个 cv::Mat 进行 frame2 的深度复制。 copyTo
的文档说:
m – Destination matrix. If it does not have a proper size or type
before the operation, it is reallocated.
这意味着,指向数据的指针会改变,但是它不会改变到 vector 内部的 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: 然而它仍然给我
error: 'class std::vector' has no member named 'forEach'
channels.forEach(Operator());
^~~~~~~ 16_vector_foreach_changedmaincode.cpp:54:31: error: expected primary-expression before '>' token
channels.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
我 trying 从我已有的 3 个不同 CV_8UC1 图像创建 1 CV_8UC3 图像,即我正在尝试分配我已有的不同单通道图像成一个单一的 1 多维图像。 下面的代码可能直接与 3 通道图像一起完美运行,但如果合并和提取它会出现运行时错误。 非法操作
#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
的浅表副本。这意味着,它们都将具有相同的 headers 和指向同一位置的数据指针。
然后你做:
frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);
对每个 cv::Mat 进行 frame2 的深度复制。 copyTo
的文档说:
m – Destination matrix. If it does not have a proper size or type before the operation, it is reallocated.
这意味着,指向数据的指针会改变,但是它不会改变到 vector 内部的 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: 然而它仍然给我
error: 'class std::vector' has no member named 'forEach' channels.forEach(Operator()); ^~~~~~~ 16_vector_foreach_changedmaincode.cpp:54:31: error: expected primary-expression before '>' token channels.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