Opencv C++ 归一化

目录

概念理解

python标准化,减均值,除标准差

opencv常用操作:

mat转float vecotr

3.4.8 normalize

3个通道分别处理

标准化减均值除方差

标准化,无for循环,效率高点

二、深度转换–convertTo()

python opencv convertTo实现;


概念理解

减去平均数除以标准差相当于对原始数据进行了线性变换,没有改变数据之间的相对位置,也没有改变数据的分布,只是数据的平均数变成0,标准差变成1。根本不会变成正态分布,除非它本来就是。

数据减去平均数再除以标准差是什么_百度知道

标准化论文说是减均值、除以方差,实际中一般都是减均值,除以标准差。

标准差的平方就是方差。图像的标准化是rgb三个通道分别处理,所以有3个值。

python标准化,减均值,除标准差

   PIXEL_MEANS = (0.5, 0.5, 0.5)  # RGB  format mean and variances
        PIXEL_STDS = (0.5, 0.5, 0.5)
        inputs=[]
        for index, img in enumerate(imgs):
            try:
                img = cv2.resize(img, (128, 128))
                img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                img=img.astype(np.float32)
                img/=255.0
                img -= np.array(PIXEL_MEANS)
                img /= np.array(PIXEL_STDS)

                img=img.transpose(2,0,1)
                t_img = torch.from_numpy(img)

opencv常用操作:

https://blog.csdn.net/jacke121/article/details/110144885

mat转float vecotr

一行代码也可以:

image是int类型,float类型都可以:

std::vector inputTensorValues=(std::vector)(image.reshape(1, 1));

vector转mat,

OpenCV实现Mat与vector,Mat与数组互转_pan_jinquan的博客-CSDN博客_mat vector

下面是封装的: 

template
vector<_Tp> convertMat2Vector(const Mat& mat)
{
	return (vector<_Tp>)(mat.reshape(1, 1));//通道数不变,按行转为一行
}



	cv::Mat dst = cv::Mat::zeros(srcResize.size(), CV_32FC3);
	srcResize.convertTo(dst, CV_32FC3);// , 10, -1);


	Mat_L2_mormal(dst);

	//for (int a = 0; a < 20; a++) {
	//	cout << (int)srcResize.at(0, a) << " ";// ok int
	//	cout << ((float*)(srcResize.data))[a] << " ";//error
	//}

	cout << "\n Mat_L2_mormal \n";

	for (int a = 0; a < 20; a++) {
		cout << (float)dst.at(0, a) << " ";// ok float

		cout << ((float*)(dst.data))[a] << " ";// ok float
		//cout << setprecision(3) << ((float*)(srcimg.data))[a] << " ";
	}
	cout << "\n CV_32FC3 \n";
	//for (int a = 0; a < 20; a++) {
	//	cout << setprecision(3) << ((double*)(dst.data))[a] << " ";//error
	//}



	vector v_mat = convertMat2Vector(dst);

3.4.8 normalize

c++默认是uint8,uchar类型,归一化需要数据转换,在3.4.8版本下,没有试验成功

在3.4.8版本下,先转换类型,再进行除法操作,也没试验成功。

这个可以:文章后面有3通道分别归一化:

Mat img = cv::imread("bar1.jpg");

	img.convertTo(img, CV_32FC1);

	normalize(img, img, 1.0, 0.0, NORM_MINMAX);

	cout << img << endl;

后面有vector的成功了,

可能是最后transpose没有做,导致的失败?

1.函数原型

void cv::normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mark=noArry())

2.函数作用

归一化数据。该函数分为范围归一化与数据值归一化。(Normalizes the norm or value range of an array.)

3.参数说明

src               输入数组;

dst               输出数组,数组的大小和原数组一致;

alpha           1,用来规范值,2.规范范围,并且是下限;

beta             只用来规范范围并且是上限;

norm_type   归一化选择的数学公式类型;

dtype           当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;

mark            掩码。选择感兴趣区域,选定后只能对该区域进行操作。

4.归一化选择的数学公式类型介绍(norm_type)

设数组中原有{A1,A2,A3...An}

NORM_L1:

NORM_INF:

NORM_L2:

NORM_MINMAX:(AK不属于{max(Ai)},min(Ai),当AK等于max(Ai)时p=1,等于min(Ai)时p=0)

6.范围归一化与值归一化的区别

区别一:范围归一化使用的是如下式子,设范围为【0,255】

即把src缩放到【0,255】这个范围内,并不使用上面的4个公式去解。

区别二:使用范围归一化时,beta必有值不等于0

举例说明:

一 值归一化:

#include

#include

using namespace std;

int main()

{

vectora={ 10,11,234,45,65,456,0 };

cv::normalize(a, a, 1,0, cv::NORM_MINMAX);

for (int i=0;i < a.size();i++)

{

cout << a[i] << endl;

}

return 0;

}

结果如下:

二 范围归一化

#include

#include

using namespace std;

int main()

{

vectora={ 10,11,234,45,65,456,0 };

cv::normalize(a, a, 0,255, cv::NORM_MINMAX);

for (int i=0;i < a.size();i++)

{

cout << a[i] << endl;

}

return 0;

}

结果如下:

Opencv C++下的Mat归一化
void Mat_L2_mormal(cv::Mat &image)
{
    //mat*mat,
    cv::Mat out;
    out=(image) .mul (image);
    float sum=0.0;
    for (int i=0;i         sum=sqrt(cv::sum(out.row(i))[0]);
        image.row(i)=(image.row(i)/sum);
    }
    out.release();
}

3个通道分别处理


原文链接:https://blog.csdn.net/wuqingshan2010/article/details/107727909

std::vector mean_value{0.406, 0.456, 0.485};
std::vector std_value{0.225, 0.224, 0.229};
cv::Mat src, dst;
std::vector bgrChannels(3);
cv::split(src, bgrChannels);
for (auto i = 0; i < bgrChannels.size(); i++)
 {
    bgrChannels[i].convertTo(bgrChannels[i], CV_32FC1, 1.0 / std_value[i], (0.0 - mean_value[i]) / std_value[i]);
}
cv::merge(bgrChannels, dst);

标准化减均值除方差

方法1只能针对float32类型的mat可以,int8的mat会报错。

//方法1
void Mat_L2_mormal(cv::Mat& image)
{
	float scale = 0.0078125f;
	float mean_value = 127.5f;
	for (int i = 0; i < image.rows; i++)
	{
		for (int j = 0; j < image.cols; j++)
		{
			image.at(i, j)[0] = (image.at(i, j)[0] - mean_value) * scale;
			image.at(i, j)[1] = (image.at(i, j)[1] - mean_value) * scale;
			image.at(i, j)[2] = (image.at(i, j)[2] - mean_value) * scale;
		}
	}

}

//方法2

double minv = 0.0, max_v = 0.0;
minMaxIdx(image1, &minv, &maxv);


for (int row = 0; row < face_img.rows; row++)
{
	for (int col = 0; col < face_img.cols; col++)
	{
		for (int k = 0; k < 3; k++) {
			const auto src = face_img.at(row, col)[k];
			auto dst = 0.0;

			if (k == 0) dst = ((float(src) / max_v - 0.485) / 0.229) ;
			if (k == 1) dst = ((float(src) / max_v - 0.456) / 0.224) ;
			if (k == 2) dst = ((float(src) / max_v - 0.406) / 0.225) ;
			inputData[k * resize_w * resize_h + row * resize_w + col] = dst;
		}
	}
}

标准化,无for循环,效率高点

std::vector AlexNet::prepareImage(std::vector &vec_img) {
    std::vector result(BATCH_SIZE * IMAGE_WIDTH * IMAGE_HEIGHT * INPUT_CHANNEL);
    float *data = result.data();
    for (const cv::Mat &src_img : vec_img)
    {
        if (!src_img.data)
            continue;
        cv::Mat flt_img;
        cv::resize(src_img, flt_img, cv::Size(IMAGE_WIDTH, IMAGE_HEIGHT));
        flt_img.convertTo(flt_img, CV_32FC3, 1.0 / 255);

        //HWC TO CHW
        std::vector split_img(INPUT_CHANNEL);
        cv::split(flt_img, split_img);

        int channelLength = IMAGE_WIDTH * IMAGE_HEIGHT;
        for (int i = 0; i < INPUT_CHANNEL; ++i)
        {
            split_img[i] = (split_img[i] - img_mean[i]) / img_std[i];
            memcpy(data, split_img[i].data, channelLength * sizeof(float));
            data += channelLength;
        }
    }
    return result;
}

二、深度转换–convertTo()


2.1、API介绍

void convertTo( OutputArray dst, int rtype, double alpha=1, double beta=0 )
1
参数dst:输出图像;
参数rtype:要转换的深度;
参数alpha:对灰度值的缩放倍数;
参数beta:对灰度值得增量。
公式: dst = satyrate_cast(src * alpha + beta);

这个也是减均值128,归一化

	cv::cvtColor(imgResized, imgResized, cv::COLOR_RGB2BGR);

	//Mat_L2_mormal(imgResized);
	vector bgr;
	cv::split(imgResized, bgr);
	bgr[0].convertTo(bgr[0], CV_32F, 1.f / 128.f, -1.f);
	bgr[1].convertTo(bgr[1], CV_32F, 1.f / 128.f, -1.f);
	bgr[2].convertTo(bgr[2], CV_32F, 1.f / 128.f, -1.f);

python opencv convertTo实现;

OpenCV-Python中没有Mat.convertTo函数怎么办?

OpenCV C++的图像对象Mat有一个函数convertTo可以把图像数据在不同的精度类型之间来回切换比如从字节到浮点数之间来回切换。非常方便,该函数的官方说明如下:

Opencv C++ 归一化_第1张图片

其中参数alpha可以让数据放缩到指定的范围内,比如从字节到浮点数类型

CV_8U 转换为CV_32Falpha=1.0/255.0时表示从0~255切换到0~1之间

浮点数类型到字节类型

CV_32F 转换为CV_8Ualpha=255时表示从0~1切换到0~255之间

同时该函数还有另外一个功能就是对超过范围的数据进行最大最小极限取值,低于0的取值0,大于255取值255。

但是到了Python中之后,很多人就会认为convertTo函数只是一个数据精度类型转换函数,不会太过关心细节,然后直接使用它。这样的结果往往导致一些细数据差异跟输出不一致问题出现。

C++/Python对比

对一张输入图像完成Sobel滤波操作,C++实现的代码如下:

Mat image = imread("D:/images/dannis1.png", IMREAD_GRAYSCALE);
imshow("input", image);
Mat m1, m2;
image.convertTo(m1, CV_32F, 1.0 / 255.0);
Mat gradx;
Sobel(m1, gradx, -1, 1, 0);
gradx.convertTo(m2, CV_8U, 255);
imshow("sobel", m2);

运行结果如下:

Opencv C++ 归一化_第2张图片

Python对应的代码如下:

import cv2 as cv
import numpy as np

image = cv.imread("D:/images/dannis1.png", cv.IMREAD_GRAYSCALE)
cv.imshow("input", image)
m1 = np.float32(image) / np.float(255)
gradx = cv.Sobel(m1, -1, 1, 0);
m2 = np.uint8(gradx * 255)
cv.imshow("sobel", m2)
cv.waitKey(0)
cv.destroyAllWindows()

运行结果如下:

Opencv C++ 归一化_第3张图片

以往的经验处理方式是先对gradx做归一化然后再显示

这个时候只需添加一行代码即可获得正确结果,把代码:

m2 = np.uint8(gradx * 255)

替换为:​​​​​​​

cv.normalize(gradx, gradx, 0, 1.0, cv.NORM_MINMAX)
m2 = np.uint8(gradx * 255)

然后再次运行,截图如下:

Opencv C++ 归一化_第4张图片

但是实际结果与C++并不一致,这个时候正确修改方式如下:

m2 = np.uint8(gradx * 255)

替换为:

cv2.normalize(gradx, gradx, 0, 1.0, cv.NORM_MINMAX)
m2 = np.uint8(np.clip(gradx * 255, 0, 255))

然后再次运行,截图如下:

Opencv C++ 归一化_第5张图片

Python版本结果跟C++保持一致了!这个很多书上跟博文并没有人提到,所以我写出来分享一下,这个技术细节点!

你可能感兴趣的:(opencv基础,c++基础,c++,opencv,计算机视觉)