14

I am trying to change 3-channel image into 4-channel like this:

cv::VideoCapture video;
video.open("sample.avi");
cv::Mat source;
cv::Mat newSrc;
int from_to = { 0,0, 1,1, 2,2, 3,3 };
for ( int i = 0; i < 1000; i ++ )
{
   video >> source;
   cv::mixChannels ( source, 2, newSrc, 1, from_to, 4 );
}

Then I got

too many input arguments in function call

for the 'mixChannels' line. Besides, I am not sure whether I am giving the arguments correctly for my goal. Can someone help me? Thank you.

sgarizvi
  • 16,623
  • 9
  • 64
  • 98
E_learner
  • 3,512
  • 14
  • 57
  • 88

3 Answers3

18

You can convert 3 channel image to 4 channel as follows:

cv::Mat source = cv::imread(path);

cv::Mat newSrc(source.size(), CV_MAKE_TYPE(source.depth(), 4));

int from_to[] = { 0,0, 1,1, 2,2, 2,3 };

cv::mixChannels(&source,1,&newSrc,1,from_to,4);

This way channel 4 will be a duplicate of channel 3. By using a negative number in the from_to list, the output channel is zero filled. eg:

int from_to[] = { 0,0, 1,1, 2,2, -1,3 };
sgarizvi
  • 16,623
  • 9
  • 64
  • 98
  • 2
    in C++11 you can also use the more convenient form `cv::mixChannels({{src, ...}}, {{dst1, ...}}, { 2,0, 1,1, 0,2, 3,3 })`. – Stefan Fisk Aug 28 '14 at 10:06
  • 1
    @sgarizvi Though myself being a complete novice in OpenCV. How `mixChannels(...)` is different from `cvtColor(motion,newmotion,CV_BGR2BGRA);` – MuneshSingh Jun 08 '17 at 16:33
7

What is the 4th channel supposed to contain? How about:

VideoCapture cap(0);
Mat frame;
cap >> frame;

Mat RGBA(frame.size(), CV_8UC4, camData);
cv::cvtColor(frame, RGBA, CV_BGR2RGBA, 4);
Herr von Wurst
  • 2,571
  • 5
  • 32
  • 53
  • Thank you for your answer. Actually I don't know what should the 4th channel contain, actually my main goal is to use "meanShiftFiltering", but it only accepts 4-channel image. So that is why I need to change. And what is "camData" in your code here? Did you mean "frame.data" ? – E_learner Nov 19 '12 at 11:31
  • 1
    it should contain alpha (transparency)? – Asalle Mar 25 '18 at 06:45
7

I think it should be like this:

cv::Mat source = cv::imread(path);
cv::Mat newSrc = cv::Mat(source.rows,source.cols,CV_8UC4);

int from_to[] = { 0,0, 1,1, 2,2, 3,3 };
cv::mixChannels(&source,1,&newSrc,1,from_to, source.channels());

In C++11 you can use initializer lists to provide multiple matrices for batch conversion inline:

cv::mixChannels({{source}}, {{newSrc}}, from_to, source.channels());

We set 3 pairs to be copied, so this leaves the 4 channel empty in newsrc. And 1 in the second and forth parameter means that the pointers source and newSrc point to one element to be processed. The last parameter gives the length of from_to.

Carsten
  • 11,287
  • 7
  • 39
  • 62
Anton Andreev
  • 2,052
  • 1
  • 22
  • 23
  • Imho, this should be the accepted answer. The answer by @sgarizvi has some issues (at least for OpenCV 3.2.0+), resulting in failed assertations, if the input image does not already contain 4 channels: the `from_to` array requires a mapping for each channel in the input array (one can solve this by passing `source.channels()` for `npairs`. Also the accepted answer has an invalid value for `nscrs`, which should be *1*. – Carsten Jun 30 '17 at 08:18