[英]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.