《数字图像处理》 第11章 表示和描述 学习笔记附部分例子代码(c++opencv)

news2024/10/2 3:24:58

表示和描述

    • 0. 前言
    • 1. 表示
      • 1.1 边界追踪
      • 1.2 链码
      • 1.3 使用最小周长多边形的多边形近似
    • 2. 边界描绘子
      • 2.1 一些简单的描绘子![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/45dddc76217e4fde93a11e2631b2a71a.png#pic_center =500x)
      • 2.2 形状数
      • 2.3 傅里叶描绘子
      • 2.4 统计矩
    • 3. 区域描绘子
      • 3.1 一些简单的描绘子
      • 3.2 拓扑描绘子
      • 3.3 纹理
    • Opencv补充:

0. 前言

本章只学习了前三节……

VS安装Image watch插件请查看官网OpenCV: Image Watch: viewing in-memory images in the Visual Studio debugger

第三版教材中图片下载地址: book images downloads

vs2019配置opencv可以查看:VS2019 & Opencv4.5.4配置教程

前情回顾:
《数字图像处理》第三章 灰度变换和空间滤波 学习笔记附部分例子代码
《数字图像处理》第四章 频率域滤波 学习笔记附部分例子代码
数字图像处理第五章 图像复原和重建(内容较简单,就没有详细记录笔记)
《数字图像处理》第六章 彩色图像处理 学习笔记附部分例子代码
《数字图像处理》第七章 小波域多分辨率处理 学习笔记附部分例子代码
数字图像处理第八章 图像压缩 非重点
《数字图像处理》第九章 形态学图像处理 学习笔记附部分例子代码
《数字图像处理》第十章 图像分割 学习笔记附部分例子代码

1. 表示

1.1 边界追踪

处理的是二值图像,其目标和背景点分别标为1和0,Moore边界追踪算法的步骤如下:

  1. 找到图像左上角为1的点b0为边界起始点。b0左边的点为c0,从c0开始按顺时针方向考察b0的8邻域,找到的第一个值1的点为b1,令扫描到b1前的点为c1。

  2. 赋值b=b1,c=c1。

  3. 从c开始顺时针方向行进,找到第一个值1的点nk,其之前的点均为背景点。

  4. 赋值b=nk,c=nk-1。

  5. 重复step3和step4,直到b=b0且下一个边界点为b1。

1.2 链码

链码用于表示由顺次连接的具有指定长度和方向的直线段组成的边界

使用了opencv的findContours()drawContours(),具体形参的表示可以看补充

void ch11_test01(string path) {
    Mat image = imread(path, IMREAD_GRAYSCALE);
    if (image.empty()) {
        cout << "Unable to load the image\n";
        return;
    }
    // 创建一个纯黑画布
    Mat black(image.size(), CV_8U, Scalar(0));

    Mat filtered;
    blur(image, filtered, Size(9, 9));

    Mat result = Otsu(filtered);//该函数的实现请看第十章笔记的3.2节

    // 寻找轮廓
    vector<vector<Point>> contours;
    findContours(result, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    vector<Point> contour = contours[0];

    vector<int> freemaCode;
    Point currentPoint = contour[0];
    Point nextPoint;

    for (size_t i = 1; i < contour.size(); i++) {
        nextPoint = contour[i];

        // 计算方向
        int dx = nextPoint.x - currentPoint.x;
        int dy = nextPoint.y - currentPoint.y;
        // 转换为佛雷曼链码
        int code = -1;
        if (dx == 0 && dy == -1)      code = 0;
        else if (dx == 1 && dy == -1) code = 1;
        else if (dx == 1 && dy == 0)  code = 2;
        else if (dx == 1 && dy == 1)  code = 3;
        else if (dx == 0 && dy == 1)  code = 4;
        else if (dx == -1 && dy == 1) code = 5;
        else if (dx == -1 && dy == 0) code = 6;
        else if (dx == -1 && dy == -1)code = 7;
        // 添加到链码序列
        freemaCode.push_back(code);
        // 更新当前点
        currentPoint = nextPoint;
    }
    // 输出佛雷曼链码
    cout << "Freeman Chain Code: ";
    for (int code : freemaCode) {
        cout << code << " ";
    }
    cout << endl;

    // 在黑布上画出轮廓
    drawContours(black, contours, -1, Scalar(128), 2);

    displayImg(image, "原图01");
    displayImg(black, "轮廓");
    waitKey(0);
}

在这里插入图片描述

1.3 使用最小周长多边形的多边形近似

数字边界可以用多边形以任意精度来近似。对于一条闭合边界,当多边形的边数等于边界上的点数时,这种近似会变得很精确,此时,每对相邻的点定义了多边形的一条边。多边形近似的目的是使用尽可能少的线段数来获取给定边界的基本形状。

2. 边界描绘子

2.1 一些简单的描绘子在这里插入图片描述

边界的长度是其最简单的描绘子之一。边界B的直径定义为

D i a m ( B ) = m a x [ D ( p i , p j ) ] Diam(B)=max[D(p_i, p_j)] Diam(B)=max[D(pi,pj)]

D是距离度量,pi和pj是边界上的两点。该直线段称为边界的长轴,边界的短边定义为与长轴垂直的直线,长轴与短轴之比称为边界的偏心率,偏心率同样是一个描述子。有时使用相邻边界线段的斜率差作为两条线段交点处曲率的描述子。

2.2 形状数

链码边界的一次差分取决于起始点。形状数的阶n定义为该链码的数字个数,形状编码不知道怎么来的,差分可看下图(方向按逆时针排序):

2.3 傅里叶描绘子

边界由坐标序列s(k)=[x(k), y(k)]表示,每个坐标对可以当做一个复数来处理

s ( k ) = x ( k ) + j y ( k ) s(k) = x(k) + jy(k) s(k)=x(k)+jy(k)

对sk进行离散傅里叶变换,使用前P个傅里叶系数进行逆变换得到

s ^ ( k ) = 1 K ∑ u = 0 P − 1 a ( u ) e j 2 π u k / P \hat s(k)=\frac{1}{K}\sum_{u=0}^{P-1}a(u)e^{j2\pi uk/P} s^(k)=K1u=0P1a(u)ej2πuk/P

由第四章得知,高频分量说明精细细节,而低频分量决定全局形状,因此,P越小,边界丢失的细节就越多。傅里叶描绘子对起始点不敏感,对平移、旋转和尺度变化不敏感。

这里教材的例子,代码复现一直有问题555555,所以就放弃放代码了

2.4 统计矩

对于一段边界,连接两个端点连接起来,然后旋转至水平得到g(r)

在这里插入图片描述

看成一个幅度直方图,纵坐标p(v)是v出现的概率估计,所以关于其均值的v的第n阶矩阵为

μ n ( v ) = ∑ i = 0 A − 1 ( v i − m ) n p ( v i ) \mu _n(v)=\sum_{i=0}^{A-1}(v_i-m)^{n}p(v_i) μn(v)=i=0A1(vim)np(vi)

式中, m = ∑ i = 0 A − 1 v i p ( v i ) m= \sum_{i=0}^{A-1}v_i p(v_i) m=i=0A1vip(vi)

m为v的均值或平均值, μ 2 \mu_2 μ2为v的方差

3. 区域描绘子

3.1 一些简单的描绘子

一个区域的面积定义为该区域中像素的数量,区域的周长是其边界的长度。致密性描绘子圆度率有下式表示:

R c = 4 π A P 2 R_c =\frac{4\pi A}{P^2} Rc=P24πA

A为讨论区域的面积,P是其周长

3.2 拓扑描绘子

拓扑学是研究未受任何变形影响的图形的性质,前提是该图形为被撕裂或粘连。区域描述有两点

  • 区域内的孔洞数量H

  • 连通分量的数量C

可以定义欧拉数E=C-H.

当描述有直线线段表示的区域非常简单,V表示顶点数,Q表示边数,F表示面数,那么欧拉公式如下:

V − Q + F = C − H V-Q+F=C-H VQ+F=CH

opencv可以使用connectedComponents()connectedComponentsWithStats()两个函数,后者会得到stats这一5列矩阵,该矩阵的每一行对应一个连通区域的标签,包含有连通区域左上角的坐标x, y,以及外接矩形的宽高和面积。

void ch11_test03(string path) {
	Mat image = imread(path, IMREAD_GRAYSCALE);
	if (image.empty()) {
		cout << "Unable to load the image\n";
		return;
	}

	Mat binaryImage;
	threshold(image, binaryImage, 78, 255, THRESH_BINARY); //阈值选择78
	binaryImage = ~binaryImage;

	//Mat labeledImg;
	//int numLabels = connectedComponents(binaryImg, labeledImg, 8);
	//numLabels--;
	Mat labeledImage;
	Mat stats, centroids;
	int numLabels = connectedComponentsWithStats(binaryImage, labeledImage, stats, centroids, 8);
	// 减去背景区域
	numLabels--;

	cout << "连通个数:" << numLabels << endl;

	//displayImg(labeledImage, "标记结果");
	displayImg(image, "原图");
	displayImg(binaryImage, "阈值处理结果");
	waitKey(0);
}


在这里插入图片描述

Stats矩阵和centroids矩阵介绍

3.3 纹理

统计方法: 一个区域的灰度级直方图的统计矩,如同3.1。二阶矩在纹理描述中特别重要,度量:

R ( z ) = 1 − 1 1 − σ 2 ( z ) R(z)=1-\frac{1}{1-\sigma ^2(z)} R(z)=11σ2(z)1

可以提现图像的平滑程度。

而三阶矩:

μ 3 ( v ) = ∑ i = 0 A − 1 ( v i − m ) 3 p ( v i ) \mu _3(v)=\sum_{i=0}^{A-1}(v_i-m)^{3}p(v_i) μ3(v)=i=0A1(vim)3p(vi)

是直方图偏斜度的度量。

“一致性”度量:

U ( z ) = ∑ L − 1 i = 0 p 2 ( z i ) U(z)=\sum_{L-1}^{i=0}p^2(z_i) U(z)=L1i=0p2(zi)

平均熵度量:

e ( z ) = ∑ i = 0 L − 1 p ( z i ) l o g 2 p ( z i ) e(z)=\sum_{i=0}^{L-1}p(z_i)log_2p(z_i) e(z)=i=0L1p(zi)log2p(zi)

令 Q 是定义两个像素彼此相对位置的一个算子,并考虑一幅具有L个可能灰度级的图像f。 令 G 为一个矩阵,其元素gij是灰度为zi和zj的像素对出现在f中由Q所指定的位置处的次数。按这种方法形成的矩阵称为灰度级共生矩阵。

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c86cbd9e6b3b4c56ba0e03ab332f1c45.png#pic_center = 500x)

图像中可能的灰度级决定了G的大小。

ch11_test04("..\\Images_CH11\\Fig1130(a)(uniform_noise).tif", "a"); //图a显示时需要归一化到0-255
ch11_test04("..\\Images_CH11\\Fig1130(b)(sinusoidal).tif", "b"); //显示时归一化到0-1
ch11_test04("..\\Images_CH11\\Fig1130(c)(cktboard_section).tif", "c");//显示时归一化到0-255

//计算共生矩阵,像素对(水平方向一格)
Mat calGLCM(Mat input, int level) {
	Mat result = Mat::zeros(Size(level, level), CV_32F);
	//遍历水平像素对
	for (int x = 0; x + 1 < input.cols; x++) {
		for (int y = 0; y < input.rows; y++) {
			int scale1 = input.at<uchar>(y, x);		//at.(row, col)
			int scale2 = input.at<uchar>(y, x + 1);
			result.at<float>(scale1, scale2)++;
		}
	}
	return result;
}


void ch11_test04(string path, string info) {
	Mat image = imread(path, IMREAD_GRAYSCALE);
	if (image.empty()) {
		cout << "Unable to load the image\n";
		return;
	}

	Mat GLCM = calGLCM(image, 256);
	//normalize(GLCM, GLCM, 0, 1, NORM_MINMAX);
	displayImg(image, "原图04" + info);
	displayImg(GLCM, "共生矩阵" + info);
	waitKey(0);
}


在这里插入图片描述

在这里插入图片描述

Opencv补充:

  1. void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method)

    • image: 输入的二值化图像,通常是通过阈值处理得到的,要求是8位单通道图像。

    • contours: 输出参数,包含检测到的轮廓的容器,通常是 vector<vector<Point>> 类型。

    • hierarchy: 输出参数,轮廓的层次结构,通常是 vector<Vec4i> 类型。可以为可选参数,如果不需要层次结构,可以设置为 noArray()

    • mode: 轮廓检索模式,可以是 RETR_EXTERNAL(仅检测外部轮廓)、RETR_LIST(检测所有轮廓,不建立层次关系)、RETR_CCOMP(检测所有轮廓,建立两层层次关系)、RETR_TREE(检测所有轮廓,建立层次树结构)。

    • method: 轮廓逼近方法,可以是 CHAIN_APPROX_NONE(保存所有的轮廓点)、CHAIN_APPROX_SIMPLE(压缩水平、垂直、对角方向的元素,只保留其端点)

  2. void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness = 1, int lineType = LINE_8);

    • image: 要绘制轮廓的图像。

    • contours: 保存轮廓点的容器,通常是vector<vector<Point>>类型

    • contourIdx: 要绘制的轮廓的索引。如果是负数,表示绘制所有轮廓。

    • color: 绘制轮廓的颜色,通常使用Scalar类表示,例如Scalar(0, 255, 0)表示绿色。

    • thickness: 绘制轮廓线的粗细,如果是负数表示填充轮廓内部。默认值是1。

    • lineType: 绘制轮廓的线型,可以是LINE_8LINE_4LINE_AA
      );`

    • image: 要绘制轮廓的图像。

    • contours: 保存轮廓点的容器,通常是vector<vector<Point>>类型

    • contourIdx: 要绘制的轮廓的索引。如果是负数,表示绘制所有轮廓。

    • color: 绘制轮廓的颜色,通常使用Scalar类表示,例如Scalar(0, 255, 0)表示绿色。

    • thickness: 绘制轮廓线的粗细,如果是负数表示填充轮廓内部。默认值是1。

    • lineType: 绘制轮廓的线型,可以是LINE_8LINE_4LINE_AA

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1362489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu同步两个剪切板

众所周知&#xff0c;ubuntu系统中有两套剪切板。第一个剪切板是用鼠标操作&#xff0c;鼠标选中则复制&#xff0c;点击鼠标中键则粘贴&#xff08;这个剪切板通常叫做——选择缓冲区&#xff09;。第二个剪切板则是真正的剪切板&#xff0c;使用ctrlc&#xff08;在终端中默认…

智慧地球(AI•Earth)社区成立一周年啦!独家福利与惊喜彩蛋等你来拿!

原文&#xff1a;智慧地球&#xff08;AI•Earth&#xff09;社区成立一周年啦&#xff01; 智慧地球社区 一周年庆典&#x1f38a; 独家福利&#x1f381;与惊喜彩蛋&#x1f389;等你来拿&#xff01; 智慧地球&#xff08;AI•Earth&#xff09;社区自2023年1月11日建立以…

HarmonyOS 应用开发学习笔记 stateStyles:多态样式

1、 HarmoryOS Ability页面的生命周期 2、 Component自定义组件 3、HarmonyOS 应用开发学习笔记 ets组件生命周期 4、HarmonyOS 应用开发学习笔记 ets组件样式定义 Styles装饰器&#xff1a;定义组件重用样式 Extend装饰器&#xff1a;定义扩展组件样式 前面记录了ets组件样式…

Java研学-web操作crud

一 思路 1 组件 页面显示&#xff1a;JSP   接受用户请求&#xff1a;Servlet   和数据库交互&#xff1a;MyBatis 2 基础准备 ① 创建 web 项目&#xff0c;导入需要依赖的 jar 包,放入 web/WEB-INF/lib目录中 ② 创建数据库表 CREATE TABLE employee( id bigint(11)…

Guarded Suspension模式--适合等待事件处理

Guarded是被守护、被保卫、被保护的意思&#xff0c; Suspension则是暂停的意思。 如果执行现在的处理会造成问题&#xff0c; 就让执行处理的线程进行等待--- 这就是Guarded Suspension模式。 模式通过让线程等待来保证实例的安全性。 一个线程ClientThread会将请求 Request的…

UE5 给自己的数字人重定向Mixamo动画

1 、准备动画骨格文件&#xff0c;动画文件&#xff0c;下面是Mixamo动画素材下载网站Mixamo动画骨格文件下载网站https://www.mixamo.com/2、下载动画骨格文件&#xff0c;打Mixamo网站&#xff0c;选择Characters骨格菜单&#xff0c;在下面找到对应的骨格。如下图所示&#…

vue3 - Element Plus 切换主题色及el-button hover颜色不生效的解决方法

vue3 - Element Plus 切换主题色及el-button hover颜色不生效的解决方法 GitHub Demo 地址 https://github.com/iotjin/jh-vue3-admin 在线预览 https://iotjin.github.io/jh-vue3-admin/ 如果您想要通过 js 控制 css 变量&#xff0c;可以这样做&#xff1a; // document.do…

Java中的Stack

Java中的Stack 在Java中&#xff0c;Stack 类是一个基于后进先出&#xff08;Last In, First Out&#xff0c;LIFO&#xff09;原则的集合类。它继承自Vector类&#xff0c;但主要被设计为提供栈的行为。 特点和用途 后进先出&#xff1a; 栈是一种后进先出的数据结构&#xff…

ROS学习笔记(11)进一步深入了解ROS第五步

0.前提 我在学习宾夕的ROS公开课的时候发现&#xff0c;外国的对计算机的教育和国内的是完全不一样的&#xff0c;当你接触了外国的课程后回头看自己学的会发现好像自己啥也没学。我这里可以放出来给大家看一下。 1.Python and C 2.Python PDB Tutorial&#xff1a;Python Deb…

Keil使用手册

文章目录 1 设置1.1 背景1.2 Project窗口显示.h文件1.3 注释1.4 Project窗口消失TAB转空格的设置keilsourceInsight 显示cannot evaluate普通局部变量静态全局变量静态局部变量 2 报错与解决2.1 warning&#xff1a;#1-D last line of file ends without anewline2.2 中文乱码 …

科研学习|论文解读——超准确性反馈:使用眼动追踪来检测阅读过程中的可理解性和兴趣

摘要&#xff1a; 了解用户想要什么信息是信息科学和技术面临的最大挑战。隐式反馈是解决这一挑战的关键&#xff0c;因为它允许信息系统了解用户的需求和偏好。然而&#xff0c;可用的反馈往往是有限的&#xff0c;而且其解释也很困难。为了应对这一挑战&#xff0c;我们提出了…

Mac打包Unix可执行文件为pkg

Mac打包Unix可执行文件为pkg 方式一&#xff1a;通过packages页面打包 1.下载packages app Distribution&#xff1a;自定义化更高&#xff0c;包括修改安装页面的内容提示 我这里主要演示Distribution模式的项目&#xff1a;通过unix可执行文件postinstall.sh脚本实现通过ma…

QT项目中添加资源文件和使用qss样式

时间记录&#xff1a;2024/1/6 一、添加使用资源文件 1.1 创建项目并打开项目&#xff08;带ui界面的项目&#xff09; 1.2 使用快捷键Ctrln创建文件&#xff0c;选择"QT"下面的"QT Resource File" 1.3 输入文件名和文件保存路径 1.4 将需要添加的文件…

Call to undefined function app\install\controller\mysqli_connect()

找到php.ini&#xff0c;放开mysqli扩展 https://stackoverflow.com/questions/25281467/fatal-error-call-to-undefined-function-mysqli-connect

FCN学习-----第一课

语义分割中的全卷积网络 CVPR IEEE国际计算机视觉与模式识别会议 PAMI IEEE模式分析与机器智能汇刊 需要会的知识点&#xff1a; 神经网络&#xff1a;前向传播和反向传播 卷积神经网络&#xff1a;CNN&#xff0c;卷积&#xff0c;池化&#xff0c;上采样 分类网络&#xff1a…

物流实时数仓:数仓搭建(DWS)一

系列文章目录 物流实时数仓&#xff1a;采集通道搭建 物流实时数仓&#xff1a;数仓搭建 物流实时数仓&#xff1a;数仓搭建&#xff08;DIM&#xff09; 物流实时数仓&#xff1a;数仓搭建&#xff08;DWD&#xff09;一 物流实时数仓&#xff1a;数仓搭建&#xff08;DWD&am…

进阶C语言学习前序

我们前期用了二十天的时间&#xff0c;学习了各种函数&#xff0c;我们已经初步具有敲写代码的能力&#xff0c;但是我们想要使用C语言去学习单片机的东西还是远远不够的&#xff0c;那么我们就需要深入了解和掌握更加深入的C语言知识&#xff0c;就有了接下来的学习计划&#…

Vmware ESXI上安装的虚拟机无法开启

背景 今天看下了Vmware ESXI上安装的虚拟机&#xff0c;点击无反应&#xff0c;也无法开启&#xff0c;日志提示“已打开电源&#xff0c;无法操作”。 注意 注意查看&#xff0c;虚拟机无法启动提示的内容。(当前磁盘文件是否可以在存储中找到&#xff0c;一般是vmdk结尾的)…

Rocky9.3 安装MySQL后如何设置初始密码

Rocky9.3 安装MySQL后如何设置初始密码 启动MySQL服务查看临时密码设置新密码 启动MySQL服务 安装MySQL后需要看一下服务是否已经启动&#xff1a; systemctl status mysqld如果没有启动的话&#xff0c;需要先启动MySQL服务&#xff1a; systemctl start mysqld # 临时启动…

Java jSerialComm库串口通信(USB RS-485/232) 查询/应答、主动上报模式

Java jSerialComm库串口通信(USB RS-485/232) 查询/应答、主动上报模式 查询/应答模式 要在Java中通过USB RS-485接口发送和接收特定的数据帧&#xff0c;你需要利用适当的串行通信库。在Java中&#xff0c;一个常见的选择是使用RXTX或jSerialComm库。这些库允许Java应用程序与…