OpenCV(8)像素归一化、图像二值化 C++

1.(cv :: normalize)范数归一化

归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。

CV_EXPORTS_W void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
                             int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
  • src:原始数组(向量)或者矩阵(将其展开当作数组).
  • dst:归一化后的结果
  • alpha:要归一化的范数值 或者为范围归一化的下边界
  • beta:范围归一化的的下边界,在范数归一化时不会使用
  • norm_type:归一化类型,有NORM_INF(无穷范数),NORM_L1(1范数),NORM_INFL2(2范数),NORM_MINMAX(范围归一化)
  • dtype:为负值时,输出数据类型和输入数据类型一致,否则 和src通道一致,depth =CV_MAT_DEPTH(dtype).
  • mask:可选的MASK

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

这个函数提供了四种归一化方式,可根据需要选择以下四个参数,下面重点说下这四种归一化方式。

- NORM_MINMAX: 数组的数值被平移或缩放到一个指定的范围,线性归一化。

在这里插入图片描述

- NORM_INF: 归一化数组的(切比雪夫距离)L∞范数(绝对值的最大值)

在这里插入图片描述

- NORM_L1 : 归一化数组的(曼哈顿距离)L1-范数(绝对值的和)

在这里插入图片描述

- NORM_L2: 归一化数组的(欧几里德距离)L2-范数

在这里插入图片描述
举例说明:
src={10, 23, 71}
NORM_L1 运算后得到: dst={0.096, 0.221, 0.683}
NORM_INF 运算后得到: dst={0.141, 0.324, 1}
NORM_L2 运算后得到: dst={0.133, 0.307, 0.947}
NORM_MINMAX 运算得到: dst={0, 0.377, 1}

//程序DEMO流程:
//读取图片--》判断并显示图片--》转换为灰度图--》转换为浮点数类型数组--》四种归一化方式
//1)scale and shift by NORM_MINMAX
//2)scale and shift by NORM_INF
//3)scale and shift by NORM_L1
//4)scale and shift by NORM_L2
//--》归一化的范围设置为1.0 - 0
//--》不同的归一化方式结果出来要乘以对应的数值
//--》将结果转换为CV_8UC1
//--》显示图片

#include"opencv2\opencv.hpp"
#include"iostream"

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    
    
    Mat src = imread("../data/test2.jpg");
    if (src.empty())
    {
    
    
        printf("Could not load image...\n");
        return -1;
    }
    imshow("srcImg", src);

    Mat src_gray, src_gray_f;
    cvtColor(src, src_gray, COLOR_RGB2GRAY);//转换为灰度图
    src_gray.convertTo(src_gray_f, CV_32F);//转换为浮点数类型数组

    //scale and shift by NORM_MINMAX
    Mat dst = Mat::zeros(src_gray.size(), CV_32FC1);
    normalize(src_gray_f, dst, 1.0, 0, NORM_MINMAX);
    Mat result = dst * 255;
    result.convertTo(dst, CV_8UC1);
    imshow("NORM_MINMAX", dst);

    //scale and shift by NORM_INF
    normalize(src_gray_f, dst, 1.0, 0, NORM_INF);
    result = dst * 255;
    result.convertTo(dst, CV_8UC1);
    imshow("NORM_INF", dst);

    //scale and shift by NORM_L1
    normalize(src_gray_f, dst, 1.0, 0, NORM_L1);
    result = dst * 100000000;
    result.convertTo(dst, CV_8UC1);
    imshow("NORM_L1", dst);

    //scale and shift by NORM_L2
    normalize(src_gray_f, dst, 1.0, 0, NORM_L2);
    result = dst * 10000;
    result.convertTo(dst, CV_8UC1);
    imshow("NORM_L2", dst);

    waitKey(0);
    return 0;
}

执行结果:
在这里插入图片描述

2.改变图像的对比度和亮度:g(i,j)=α⋅f(i,j)+β

在这里插入图片描述

new_image(i,j) = alpha*image(i,j) + beta
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
double alpha; /**< 控制对比度 */
int beta;    /**< 控制亮度 */
int main(int argc, char** argv)
{
    
    
    // 读入用户提供的图像
    Mat image = imread("../data/test2.jpg");
    Mat new_image = Mat::zeros(image.size(), image.type()); //初始像素值等于零,与原始图像相同的大小和类型
    // 初始化
    cout << " Basic Linear Transforms " << endl;
    cout << "-------------------------" << endl;
    cout << "* Enter the alpha value 输入alpha值:[1.0-3.0]: ";
    cin >> alpha;
    cout << "* Enter the beta value 输入beta值:[0-100]: ";
    cin >> beta;
    //要执行我们将访问图像中的每个像素。由于我们使用BGR图像,
    //我们将每像素(B,G和R)有三个值,因此我们也将分别访问它们
    // 执行运算 new_image(i,j) = alpha*image(i,j) + beta
    for (int y = 0; y < image.rows; y++)
    {
    
    
        for (int x = 0; x < image.cols; x++)
        {
    
    
            for (int c = 0; c < 3; c++)
            {
    
    
                new_image.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(alpha * (image.at<Vec3b>(y, x)[c]) + beta);
            }
        }
    }
    namedWindow("Original Image", 1);// 创建窗口
    namedWindow("New Image", 1);// 创建窗口
    imshow("Original Image", image);// 显示图像
    imshow("New Image", new_image);// 显示改变后图像
    waitKey();// 等待用户按键
    return 0;
}

2.1.(cv :: src.convertTo)缩放并转换到另外一种数据类型

我们可以不用 for 循环来访问每个像素,而是直接采用下面这个命令:

src.convertTo(dst, type, scale, shift)
  • src:img参数为图像数据来源,其类型为Mat。
  • dst:目的矩阵;
  • type:需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用-1)则输出矩阵和输入矩阵类型相同;
  • scale:比例因子;
  • shift:将输入数组元素按比例缩放后添加的值;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
double alpha; /**< 控制对比度 */
int beta;    /**< 控制亮度 */
int main(int argc, char** argv)
{
    
    
    // 读入用户提供的图像
    Mat image = imread("../data/test3.jpg");
    Mat new_image = Mat::zeros(image.size(), image.type()); //初始像素值等于零,与原始图像相同的大小和类型
    // 初始化
    cout << " Basic Linear Transforms " << endl;
    cout << "-------------------------" << endl;
    cout << "* Enter the alpha value 输入alpha值:[1.0-3.0]: ";
    cin >> alpha;
    cout << "* Enter the beta value 输入beta值:[0-100]: ";
    cin >> beta;
    // 执行运算 new_image(i,j) = alpha*image(i,j) + beta
    //我们可以不用 for 循环来访问每个像素,而是直接采用下面这个命令:
    image.convertTo(new_image, -1, alpha, beta);
    namedWindow("Original Image", 1);// 创建窗口
    namedWindow("New Image", 1);// 创建窗口
    imshow("Original Image", image);// 显示图像
    imshow("New Image", new_image);// 显示改变后图像
    waitKey();// 等待用户按键
    return 0;
}

以上两种方法的执行结果:

 Basic Linear Transforms
-------------------------
* Enter the alpha value 输入alpha值:[1.0-3.0]: 2.2
* Enter the beta value 输入beta值:[0-100]: 50

在这里插入图片描述

3.(cv :: hconcat)和(cv :: vconcat)图像拼接函数

#include <iostream>
#include <core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
    
    
	Mat combine, combine1, combine2;
	Mat a = imread("../data/test2.jpg");
	Mat b = imread("../data/test2.jpg");
	Mat c = imread("../data/test2.jpg");
	Mat d = imread("../data/test2.jpg");
	hconcat(a, b, combine1);	//水平拼接
	hconcat(c, d, combine2);	//水平拼接
	vconcat(combine1, combine2, combine);	//垂直拼接
	namedWindow("Combine", WINDOW_AUTOSIZE);
	imshow("Combine", combine);
	waitKey(0);
	system("pause");
	return 0;
}

执行结果:
在这里插入图片描述

4.图像二值化

图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。

4.1.(cv :: threshold)图像二值化

double threshold( InputArray src,OutputArray dst,double threshold,double maxval,int type );
  • src:原始数组,可以是Mat类型。
  • dst:输出数组,必须与 src 的类型一致。
  • threshold:阈值
  • maxval:使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值。
  • type:阈值类型
    type=CV_THRESH_BINARY:如果 src(x,y)>threshold ,dst(x,y) = max_value; 否则,dst(x,y)=0;
    type=CV_THRESH_BINARY_INV:如果 src(x,y)>threshold,dst(x,y) = 0; 否则,dst(x,y) = max_value.
    type=CV_THRESH_TRUNC:如果 src(x,y)>threshold,dst(x,y) = max_value; 否则dst(x,y) = src(x,y).
    type=CV_THRESH_TOZERO:如果src(x,y)>threshold,dst(x,y) = src(x,y) ; 否则 dst(x,y) = 0。
    type=CV_THRESH_TOZERO_INV:如果 src(x,y)>threshold,dst(x,y) = 0 ; 否则dst(x,y) = src(x,y).
#include "opencv2/imgproc/imgproc.hpp"  
#include "opencv2/highgui/highgui.hpp"  
using namespace cv;
using namespace std;
int main()
{
    
    
	//定义变量
	Mat img = imread("./image/test3.jpg");
	imshow("原图", img);
	//灰度化处理
	cvtColor(img, img, COLOR_BGR2GRAY);
	imshow("灰度化处理", img);
	// 转为二值图  
	threshold(img, img, 100, 255, THRESH_BINARY); 
	//adaptiveThreshold(img, img, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 45, 10);
	imshow("二值化后的图像", img);
	waitKey(0);
	return 0;
}

执行结果:
在这里插入图片描述

4.2.自定义图像二值化

这个语句的意思是,如果阈值小于100,那么中间为真,即像素值小于70的为1,大于70的为0;如果阈值大于100,那么右边为真,即像素值大于70的为1,小于70的为0.

#include "opencv2/imgproc/imgproc.hpp"  
#include "opencv2/highgui/highgui.hpp"  
using namespace cv;
using namespace std;
void main()
{
    
    
	Mat img;
	int threshval = 170;//设定阈值
	Mat result;
	Mat bw = img;
	img = imread("./image/test6.jpg", 0);
	imshow("原图", img);
	bw = threshval < 100 ? (img < 70) : (img > 70);//二值化
	imshow("二值化后的图像", bw);
	waitKey(0);
}

执行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/soinlove36/article/details/119853000
今日推荐