c++中的OpenCV整数除法不符合预期

6g8kf2rb  于 2023-03-19  发布在  其他
关注(0)|答案(4)|浏览(192)

给定以下输出:
[11233、11345、11434、10897] [44、44、45、43] [-31、81、-86、-111]
从这个代码

std::cout << mat32sc1;
channels[1] = mat32sc1 / 256;
channels[0] = mat32sc1 - channels[1] * 256;
std::cout << channels[1];
std::cout << channels[0];

我本来期望11233 / 256是43,使用整数除法?
我的假设是错误的,c++总是做整数除以地板?

更新

下面是我当前的编码函数。

void encode(cv::Mat & src, cv::Mat & dst)
{
    cv::Mat_<int> mat32sc1;
    src.convertTo(mat32sc1, CV_32SC1, 10, 11000);

    std::vector<cv::Mat> channels;
    channels.resize(3);

//  bitwise_and(mat32sc1, cv::Scalar(255), channels[0]); // is this needed or will converTo truncate automaticly.
//  channels[0].convertTo(channels[0], CV_8UC1);
//  mat32sc1.convertTo(channels[1], CV_8UC1, 1.0 / (1 << 8));
    channels[2] = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);
    int flag = 256;
//  std::cout << mat32sc1;
    channels[1] = mat32sc1 / flag;
    channels[0] = mat32sc1 - channels[1] * flag;
    cv::Mat_<int> off = (channels[0] < 0) / 255;
    //std::cout << off;
    channels[1] -= off;
    channels[0] = mat32sc1 - channels[1] * flag;

    //std::cout << channels[1];
    //std::cout << channels[0];
    channels[0].convertTo(channels[0], CV_8UC1);
    channels[1].convertTo(channels[1], CV_8UC1);

    cv::merge(channels, dst);
}

有没有更聪明的方法能得到同样的结果

0ve6wy6x

0ve6wy6x1#

除法确实不是整数除法。OpenCV中的大多数函数将它们的输入转换为标量,标量是1、2、3或4个双精度数的容器。OpenCV中的其他函数执行类似的操作(scaleAdd、addWeighted、convertTo等)都可以使用双精度型。换句话说,你的代码执行了双精度除法和四舍五入。这就是为什么你得到了44而不是43。

编辑:

至于“encode”函数,你不需要执行复杂的操作,新矩阵的字节已经存在了,你只需要创建一个方便的访问方式:

Mat temp(src.size(), CV_8UC4, src.data);

这将创建指向src数据的新矩阵头(即没有数据副本),但数据不是单通道的整数矩阵,而是无符号字符的4通道矩阵(宽度和高度相同)。拆分()、合并()、混合通道()等。

inkz8wg9

inkz8wg92#

不,你是对的,整数除法在C++中是通过取整来执行的。参见 [expr.穆尔]
对于整数操作数,/运算符生成代数商,并丢弃任何小数部分;81
81)这通常称为向零截断。

wrrgggsh

wrrgggsh3#

这是一个手工制作的函数,可以在OpenCV上执行整数除法,希望对大家有所帮助。

#include "opencv2\highgui.hpp"
using cv::Mat;
#include "opencv2\imgproc.hpp"
using cv::threshold;
void IntegerDivide(Mat& Input_Dividendo, int Input_Divisor, Mat& Output_Cociente, Mat& Output_Resto)
{
    // Input_Dividendo is supposed to be CV_32S
    // Input_Dividendo = Input_Divisor * Output_Cociente + Output_Resto

    Mat candidato_Cociente=Input_Dividendo/Input_Divisor;
    Mat offset=Input_Dividendo-(candidato_Cociente*Input_Divisor);
    Mat error_en_candidato_Cociente;

    // Threshold
    // threshold( offset, error_en_candidato_Cociente, 0, 1,CV_THRESH_BINARY_INV);
    Mat aux_src;
    offset.convertTo(aux_src,CV_32F);
    Mat aux_dst;
    threshold( aux_src, aux_dst, 0, 1,CV_THRESH_BINARY_INV);
    aux_dst.convertTo(error_en_candidato_Cociente,CV_32S);  
    // End threshold

    Output_Cociente=candidato_Cociente-error_en_candidato_Cociente;

    Output_Resto=Input_Dividendo-(Output_Cociente*Input_Divisor);
}
j2datikz

j2datikz4#

我认为整数除法的一个简单向量解决方案(不舍入)是在除法之前删除相同数量的位以实现所需的位移位。例如,我使用CV_16U并尝试右移4位。我首先屏蔽掉0xFFF 0:
//位右移4位,带输入“frameMat”CV_16U的取整功能
cv::垫框架垫屏蔽;
cv::按位与(帧掩码,0xFFF 0,帧掩码);
帧材质屏蔽转换为(移位材质,CV_8U,(1.0 / 16.0));

相关问题