简体   繁体   中英

OpenCV Mat::convertTo(type) does not convert the type

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?

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.

Ie 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 eg 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);

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM