GIVEN:
The following code fragment:
#include <opencv2/core.hpp>
#include <iostream>
int
main(int argc, char** argv)
{
cv::Mat a = (cv::Mat_<double>(3,1) << 1, 2, 3);
cv::Mat b;
std::cout << "a(before): " << cv::typeToString(a.type()) << std::endl;
std::cout << "b(before): " << cv::typeToString(b.type()) << std::endl;
std::cout << std::endl;
std::cout << "Convert 'a' --> 'b' with type CV_64FC4" << std::endl;
std::cout << std::endl;
a.convertTo(b, CV_64FC4);
std::cout << "a(after): " << cv::typeToString(a.type()) << std::endl;
std::cout << "b(after): " << cv::typeToString(b.type()) << std::endl;
return 0;
}
EXPECTATION:
Should produce, in my understanding, the following output:
a(before): CV_64FC1
b(before): CV_8UC1
Convert 'a' --> 'b' with type CV_64FC4
a(after): CV_64FC1
b(after): CV_64FC4
OUTPUT:
Instead, the output is as follows:
a(before): CV_64FC1
b(before): CV_8UC1
Convert 'a' --> 'b' with type CV_64FC4
a(after): CV_64FC1
b(after): CV_64FC1
QUESTION:
What is going on here? How can I actually convert to the specified target type?
CodePudding user response:
Short answer:
cv::Mat::convertTo
does not support changing the number of channels.
Longer answer:
As you can see in the documentation regarding the rtype
paremeter of cv::Mat::convertTo
(the one you pass CV_64FC4
to):
desired output matrix type or, rather, the depth since the number of channels are the same as the input has; if rtype is negative, the output matrix will have the same type as the input.
I.e. convertTo
does not handle the case of changing the number of channels (only the bit depth of each channel).
Although it is not documented explicitly, I guess cv::Mat::convertTo
extracts the bit depth from rtype
and ignores the number of channels.
In your example: a
has a single channels, and therefore so is b
after the conversion.
In order to see the effect of convertTo
, you can pass e.g. CV_32FC1
in order to convert 64 bit double
s to 32 bit float
s.
Update:
According to the OP's request (in the comments below), here are examples of changing the number of channels using cv::mixChannels
:
cv::Mat img1c = (cv::Mat_<double>(3, 1) << 1, 2, 3);
cv::Mat img4c(img1c.size(), CV_64FC4);
cv::Mat img1c_2(img1c.size(), CV_64FC1);
// Convert 1 channel into 4 (duplicate the channel):
std::vector<int> fromTo1{ 0,0, 0,1, 0,2, 0,3 }; // 0->0, 0->1, 0->2, 0->3
cv::mixChannels(img1c, img4c, fromTo1);
// Convert back to 1 channel (pick one of the channels - the 1st one in this case):
std::vector<int> fromTo2{ 0,0 }; // 0->0 (pick the 1st channel)
cv::mixChannels(img4c, img1c_2, fromTo2);
CodePudding user response:
As I've commented in your other question, if you want to rearrange a Nx1 4-channel Mat to Nx4 1-channel, then you need to use cv::Mat::reshape()
some_mat.reshape(1)
converts from Nx1 K-channel (CV_64FC4) to NxK 1-channel (CV_64FC1)
Docs: https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a4eb96e3251417fa88b78e2abd6cfd7d8
You really don't need any of that though, because you say you want matrix multiplication... or rather matrix-vector products. you can have that with cv::transform
. transform does matrix-vector multiplication, also for lists of vectors (Nx1 K-channel matrices, also NxK 1-ch).