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

18 篇文章 9 订阅

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);
}

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

要实现最小误判概率法图像二值化功能,可以按照以下步骤进行: 1. 读入原始图像,并将其转换为灰度图像。 2. 计算灰度直方图,并根据直方图进行灰度值的归一化。 3. 根据设定的阈值,将像素点分为两类:前景(白色)和背景(黑色)。 4. 计算分类结果的误判概率,如果误判概率大于设定的阈值,则重新选择阈值。 5. 将二值化后的图像输出。 下面是一个简单的 C++ 代码示例: ```c++ #include <iostream> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { Mat img = imread("image.jpg", IMREAD_GRAYSCALE); // 读入原始图像并转换为灰度图像 int hist[256] = {0}; // 定义灰度直方图 int rows = img.rows, cols = img.cols; for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { int pixel = img.at<uchar>(i, j); hist[pixel]++; } } double prob[256] = {0}; // 定义灰度值归一化概率 for(int i = 0; i < 256; i++) { prob[i] = (double) hist[i] / (rows * cols); } double threshold = 0.5; // 初始阈值 double min_error = 1.0; // 初始误判概率 while(min_error > 0.01) { // 设置误判概率的最小值 double w0 = 0.0, w1 = 0.0, u0 = 0.0, u1 = 0.0; for(int i = 0; i < 256; i++) { if(prob[i] == 0) continue; if(i < threshold * 255) { w0 += prob[i]; u0 += i * prob[i]; } else { w1 += prob[i]; u1 += i * prob[i]; } } u0 /= w0; u1 /= w1; double cur_error = w0 * w1 * (u0 - u1) * (u0 - u1); // 计算当前误判概率 if(cur_error < min_error) { min_error = cur_error; } else { break; } threshold += 0.01; // 阈值加上一个步长 } Mat binary; threshold(img, binary, threshold * 255, 255, THRESH_BINARY); // 二值化处理 imshow("Binary image", binary); waitKey(0); return 0; } ``` 代码中使用了 OpenCV 库,可以通过以下命令安装: ```bash sudo apt-get install libopencv-dev ``` 运行程序后,会显示二值化后的图像
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~晓广~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值