2019-05-28 02:33:38 qq_44709563 阅读数 288
  • 互联网产品经理小白入门必修课

    以培训产品经理为目标,通过课程学习,对行业及产品经理岗位有基础认知,了解一个合格产品经理应该具备的能力和素质,掌握基础的工具,能够完成简单的原型制作,学习者达到初级到入门。

    8252 人正在学习 去看看 邓轰轰

数字图像处理第一面:高斯滤波与中值滤波

这个学期,由于脑袋抽风涉嫌装逼(不是),校选课选了四大名挂之数字图像处理- -。但在慢慢深入学习之后,却渐渐对其产生了兴趣(真香)

在这里插入图片描述

于是在朋友和百度的帮助下,总算是完成了最后的拙作。我选择的是数字图像处理中的高斯滤波和中值滤波的实现,话不多说,正文开始:

小小的介绍

在实现滤波操作之前,需要先介绍一下数字图像处理中图像的噪声和卷积

图像噪声是指存在于图像数据中的不必要的或多余的干扰信息。各类图像处理系统在图像的采集、获取、传送和转换(如成像、复制扫描、传输以及显示等)过程中,均处在复杂的环境中,光照、电磁多变,所有的图像均不同程度地被可见或不可见的噪声干扰,导致图像质量的下降,掩盖图片重要细节
而图像噪声的去除在数字图像处理技术中的重要性越来越明显,如高放大倍数航片的判读,X射线图像系统中的噪声去除等已经成为不可缺少的技术步骤。

卷积:其实就是一个带权值的n维矩阵(这里也叫滤波器)在图像的像素图上滚来滚去对每个像素点进行加权运算,滚完了滤波也就做完了~
在这里插入图片描述

总所周知,图片其实是有千万个像素组成的,而每个像素点,其实就是表示图像的二维数组中的每个房间地址,灰度值,就是每个房间中的值。在图像的生成过程中,由于不可控因素,会造成临近灰度值所形成的函数的导数过大——也就是噪声,让其与真实颜色产生误差,掩盖图片细节,之后的各种后期图像处理便会不断放大这种误差。
而滤波则是对图片预处理时消除噪音的一种重要方式。

这里再简单的介绍一下高斯滤波和中值滤波

高斯滤波的滤波器中的权值的计算公式就是他啦~也就是高斯滤波名字的由来啦!

中值滤波正如其名,它是将像素(中值计算中包括的原像素值)邻域内灰度的中值代替该像素的值,也就是我们在图像中取3*3的矩阵,里面有9个像素点,我们将9个像素进行排序,最后将这个矩阵的中心点赋值为这九个像素的中值

函数原型

介绍了这么多,其实滤波器复杂的运算并不需要我们去实现,opencv中提供了medianBlur()和GaussianBlur()函数来实现中值滤波和高斯滤波的操作。原型如下:

C++: void medianBlur(InputArray src, OutputArray dst, int ksize)

参数解释:

  • IputArray src: 输入图像,图像为1、3、4通道的图像,当模板尺寸为3或5时,图像深度只能为CV_8U、CV_16U、CV_32F中的一个,如而对于较大孔径尺寸的图片,图像深度只能是CV_8U。
  • OutputArray dst: 输出图像,尺寸和类型与输入图像一致,可以使用Mat::Clone以原图像为模板来初始化输出图像dst
  • int ksize: 滤波器模板的尺寸大小,必须是大于1的奇数,如3、5、7…
C++:void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                double sigmaX, double sigmaY = 0,
                                int borderType = BORDER_DEFAULT );

参数解释:

  • InputArray src:输入图像,通道不限,各通道单独处理;深度应当是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F
  • OutputArray dst:输出图像,尺寸和类型与输入图像一致
  • Size ksize:高斯滤波器模板的大小,也是要大于1的奇数
  • double sigmaX, double sigmaY = 0:高斯滤波器在X方向上的标准差,而sigmaY=0时,其值自动由sigmaX确定。
  • borderType为边缘点插值类型。(4,5点稍显晦涩,感兴趣的可以百度了解一下)

实现过程

QSecond.h

#pragma once
#ifndef QSecond_H
#define QSecond_H

#include <QtWidgets/QMainWindow>
#include "ui_QSecond.h"
#include <QMainWindow>
#include <QFileDialog>
#include <QDir>
#include <QFile>

namespace Ui {//namespace:命名空间Ui:区分不同代码作者的相同函数名,相当于不同文件夹下的相同文件名得以区分
	class MainWindow;//空间成员
}

class QSecond : public QMainWindow
{
	Q_OBJECT

public:
	explicit QSecond(QWidget *parent = nullptr);//使用explcit防止Qsecond被自动地隐式类型转换
	~QSecond();//析构函数

private slots://private:只能在定义它的类QSecond中使用
	void on_inputPushButton_pressed();
	void on_outputPushButton_pressed();
	void on_savePushButton_pressed();
	void on_showPushButton_pressed();

private://只能在定义它的类中使用
	Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

QSecond.cpp:

在这里插入图片描述

#include "QSecond.h"
#include "ui_QSecond.h"
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>


QSecond::QSecond(QWidget *parent) ://QWidget:所有用户界面对象的基类。
	QMainWindow(parent),//创建主界面
	ui(new Ui::MainWindow)
{
	ui->setupUi(this);
}

QSecond::~QSecond()//析构函数:在QSecond类使用完后自动删除(抛弃)
{
	delete ui;
}

void QSecond::on_inputPushButton_pressed()//Input键功能实现
{
	QString fileName = QFileDialog::getOpenFileName(this,//Q:FileDialogL-文件选择窗口。
		"Open Input Image",
		QDir::currentPath(),//获取当前工作目录
		"Images (*.jpg *.png *.bmp)");
	if (QFile::exists(fileName)) {
		ui->inputLineEdit->setText(fileName);
	}
}
void QSecond::on_outputPushButton_pressed()//Output键功能实现
{
	QString fileName = QFileDialog::getSaveFileName(this,
		"Select Output Image",
		QDir::currentPath(),
		"*.jpg;;*.png;;*.bmp");
	if (!fileName.isEmpty())
		ui->outputLineEdit->setText(fileName);
}

void QSecond::on_savePushButton_pressed()//Save键功能实现
{
	if (!ui->outputLineEdit->text().isEmpty()) {
		cv::Mat inImg, outImg;
		inImg = cv::imread(ui->inputLineEdit->text().toStdString());
		if (ui->medianBlurRadioButton->isChecked())
			cv::medianBlur(inImg, outImg, 5);
		else if (ui->gaussianBlurRadioButton->isChecked())
			cv::GaussianBlur(inImg, outImg, cv::Size(5, 5), 1.25);
		if (ui->displayImageCheckBox->isChecked())//dispaly键功能实现
			cv::imshow("Output Img", outImg);
	}
}

void QSecond::on_showPushButton_pressed()//Show键功能实现
{
	if (ui->gaussianBlurRadioButton->isChecked() | ui->medianBlurRadioButton->isChecked())//ischecked:该键是否被选中
		if (!ui->inputLineEdit->text().isEmpty()) {
			cv::Mat inImg, outImg;//初始化定义两个图像:输入输出图
			inImg = cv::imread(ui->inputLineEdit->text().toStdString());//imread读取图像
			if (ui->medianBlurRadioButton->isChecked())
				cv::medianBlur(inImg, outImg, 5);//5:滤波模板尺寸大小
			else if (ui->gaussianBlurRadioButton->isChecked())
				cv::GaussianBlur(inImg, outImg, cv::Size(5, 5), 1.25);//5.5为高斯滤波模板器尺寸,1.25为边缘点插值类型大小
			cv::namedWindow("Input Img",cv::WINDOW_NORMAL);//窗口命名。NORMAL:窗口可以通过拖动改变大小
			cv::namedWindow("Output Img",cv::WINDOW_NORMAL);//AUTOSIZE:窗口大小等于图片大小
			cv::imshow("Input Img", inImg);//imshow:输出图像
			cv::imshow("Output Img", outImg);
			if (cv::waitKey(200) == 27)//waitKey:不断刷新图像,刷新率为200ms.当输入键值为27(ESC)时,停止刷新,关闭窗口
				cv::destroyAllWindows();
		}
}	


main.cpp

#include "QSecond.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);//创建对象
	QSecond w;
	w.show();//显示无模式对话框。(无模式:即可以切换焦点程序)
	return a.exec();//程序进程开始
}

  • 详细解释都在注释中~

测试数据

在这里插入图片描述
高斯:
在这里插入图片描述
中值:
在这里插入图片描述

在这里插入图片描述
高斯:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
高斯:
在这里插入图片描述
中值:
在这里插入图片描述

在这里插入图片描述
高斯:
在这里插入图片描述

中值:
在这里插入图片描述

  • 因为滤波操作只是图片的预处理,简单的进行去噪,所以不会有太大的变化,不然就是本末倒置了。
  • 当然,可以通过修改滤波器模板的尺寸大小和边缘点插值大小来使效果更加明显。
  • 安装了OpenCV与QT creator

结语

因为我也是初学,所以大多还只是略懂皮毛,但这次的实验也让我打开了一扇新的大门,后面等待的是更多未知的有趣的代码与知识。希望在未来,还能在这里与大家分享自己摸爬滚打的学习经验~

最后的彩蛋

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>


int main(int argc, char* argv[])
{
	using namespace cv;
	using namespace std;
	Mat img;
	VideoCapture cap;
	cap.open(0);
	if (!cap.isOpened())
		return 0;
	namedWindow("JT", WINDOW_NORMAL);
	while (1)
	{
		cap >> img;
		if (img.empty())
			break;
		imshow("JT", img);
		if (waitKey(30) == 27)
			break;
	}
	destroyAllWindows();
	return 0;
}

别问运行后是什么,问就是蔡徐坤/滑稽脸

下次再见~

2016-02-26 17:48:13 baimafujinji 阅读数 66275
  • 互联网产品经理小白入门必修课

    以培训产品经理为目标,通过课程学习,对行业及产品经理岗位有基础认知,了解一个合格产品经理应该具备的能力和素质,掌握基础的工具,能够完成简单的原型制作,学习者达到初级到入门。

    8252 人正在学习 去看看 邓轰轰

什么是数字图像处理?历史、以及它所研究的内容。

 

说起图像处理,你会想到什么?你是否真的了解这个领域所研究的内容。纵向来说,数字图像处理研究的历史相当悠久;横向来说,数字图像处理研究的话题相当广泛。

数字图像处理的历史可以追溯到近百年以前,大约在1920年的时候,图像首次通过海底电缆从英国伦敦传送到美国纽约。图像处理的首次应用是为了改善伦敦和纽约之间海底电缆发送的图片质量,那时就应用了图像编码,被编码后的图像通过海底电缆传送至目的地,再通过特殊设备进行输出。这是一次历史性的进步,传送一幅图片的时间从原来的一个多星期减少到了3小时。

1950年,美国的麻省理工学院制造出了第一台配有图形显示器的电子计算机——旋风I号(Whirlwind I)。旋风I号的显示器使用一个类似于示波器的阴极射线管(Cathode Ray Tube,CRT)来显示一些简单的图形。1958年美国Calcomp公司研制出了滚筒式绘图仪,GerBer公司把数控机床发展成为平板式绘图仪。在这一时期,电子计算机都主要应用于科学计算,而为这些计算机配置的图形设备也仅仅是作为一种简单的输出设备。

随着计算机技术的进步,数字图像处理技术也得到了很大的发展。1962年,当时还在麻省理工学院攻读博士学位的伊凡·苏泽兰(Ivan Sutherland)成功开发了具有划时代意义的“画板”(Sketchpad)程式。而这正是有史以来第一个交互式绘图系统,同时这也是交互式电脑绘图的开端。从此计算机和图形图像被更加紧密地联系到了一起。鉴于伊凡·苏泽兰为计算机图形学创立所做出的杰出贡献,他于1988年被授予计算机领域最高奖——图灵奖。

1964年,美国加利福尼亚的喷气推进实验室用计算机对“旅行者七号”太空船发回的大批月球照片进行处理,以校正航天器上摄影机中各种类型的图像畸变,收到了明显的效果。在后来的宇航空间技术中,数字图像处理技术都发挥了巨大的作用。

到了20世纪60年代末期,数字图像处理已经形成了比较完善的学科体系,这套理论在20世纪70年代发展得十分迅速,并开始应用于医学影像和天文学等领域。1972年,美国物理学家阿伦·马克利奥德·柯麦科(Allan MacLeodCormack)和英国电机工程师戈弗雷·纽博尔德·豪恩斯弗尔德(Godfrey Newbold Housfield)发明了轴向断层术,并将其用于头颅诊断。世界第一台X射线计算机轴向断层摄影装置由EMI公司研制成功,这也就是人们通常所说的CT(Computer Tomograph)。CT可通过一些算法用感知到的数据去重建通过物体的“切片”图像。这些图像组成了物体内部的再现图像,也就是根据人的头部截面的投影,经计算机处理来进行图像重建。鉴于CT对于医学诊断技术的发展所起到的巨大推动作用,柯麦科和豪恩斯弗尔德于1979年获得了诺贝尔生理或医学奖。

随后在2003年,诺贝尔生理或医学奖的殊荣再次授予了两位在医疗影像设备研究方面做出杰出贡献的科学家——美国化学家保罗·劳特伯尔(Paul Lauterbur)和英国物理学家彼得·曼斯菲尔(Peter Mansfield)。两位获奖者在利用磁共振成像(Magnetic Resonance Imaging,MRI)显示不同结构方面分别取得了开创性成就。瑞典卡罗林斯卡医学院称,这两位科学家在MRI领域的开创性工作,代表了医学诊疗和研究的重大突破。而事实上,核磁共振的成功同样也离不开数字图像处理方面的发展。即使在今天,诸如MRI图像降噪等问题依然是数字图像处理领域的热门研究方向。

说到数字图像的发展历程,还有一项至关重要的成果不得不提,那就是电荷耦合元件(Charge-coupled Device,CCD)。CCD最初是由美国贝尔实验室的科学家维拉德·波义耳(Willard Sterling Boyle)和乔治·史密斯(George Elwood Smith)于1969年发明的。CCD的作用就像胶片一样,它能够把光学影像转化为数字信号。今天人们所广泛使用的数码照相机、数码摄影机和扫描仪都是以CCD为基础发展而来的。换句话说,我们现在所研究的数字图像主要也都是通过CCD设备获取的。由于波义耳和史密斯在CCD研发上所做出的巨大贡献,他们两人共同荣获了2009年度的诺贝尔物理学奖。

数字图像处理在今天是非常热门的技术之一,生活中无处不存在着它的影子,可以说它是一种每时每刻都在改变着人类生活的技术。但长久以来,很多人对数字图像处理存在着较大的曲解,人们总是不自觉地将图像处理和Photoshop联系在一起。大名鼎鼎的Photoshop无疑是当前使用最为广泛的图像处理工具。类似的软件还有Corel公司生产的CorelDRAW等软件。

尽管Photoshop是一款非常优秀的图像处理软件,但它的存在并不代表数字图像处理的全部理论与方法。它所具有的功能仅仅是数字图像处理中的一部分。总的来说,数字图像处理研究的内容主要包括如下几个方面:

  • 1)图像获取和输出
  • 2)图像编码和压缩
  • 3)图像增强与复原
  • 4)图像的频域变换
  • 5)图像的信息安全
  • 6)图像的区域分割
  • 7)图像目标的识别
  • 8)图像的几何变换

但图像处理的研究内容,又不仅限于上述内容!所以说图像处理的研究话题是相当宽泛的。那现在图像处理都应用在哪些领域呢?或许我们可能熟知的例子有(当然,你应该还能举出更多例子):

  • 1)一些专业图像处理软件:Photoshop、CorelDRAW……
  • 2)一些手机APP应用:美图秀秀、玩图……
  • 3)一些医学图像处理应用:MRI、彩超图像处理……
  • 4)一些制造业上的应用:元器件检测、瑕疵检测……
  • 5)一些摄像头、相机上的应用:夜间照片的质量改善……
  • 6)一些电影工业上是应用:换背景、电影特技……

 

什么样的人会去学(或者需要学)图像处理?

 

1)如果你是我上述那些应用领域的从业者,你当然需要掌握图像方面的理论和技术;2)相关专业的研究人员、大专院校的博士生、研究生。

所谓相关专业又是指什么呢?这个答案也可能相当宽泛,例如(但不仅限于此):Computer Science, Software Engineering, Electronic Engineering, Biomedical Engineering, Automation, Control, Applied Mathematics……

 

如何学好图像处理——我的一些箴言

 

1)对于初级入门者

 

一个扎实的基础和对于图像处理理论的完整的、系统的整体认识对于后续的深入研究和实践应用具有非常非常重要的意义。

我经常喜欢拿武侠小说《天龙八部》中的一段情节来向读者说明此中的道理,相信读者对这部曾经被多次搬上银幕的金庸作品已经耳熟能详了。书中讲到有个名叫鸠摩智的番僧一心想练就绝世武学,而且他也算是个相当勤奋的人了。但是,他错就错在太过于急功近利,甚至使用道家的小无相功来催动少林绝技。看上去威力无比,而且可以在短时间内“速成”,但实则后患无穷。最终鸠摩智走火入魔,前功尽废,方才大彻大悟。这个故事其实就告诉我们打牢基础是非常重要的,特别是要取得更长足的发展,就更是要对基本原理刨根问底,力求甚解,从而做到庖丁解牛,游刃有余。

一些看似高深的算法往往是许多基础算法的组合提升。例如,令很多人望而却步的SIFT特征构建过程中,就用到了图像金字塔、直方图、高斯滤波这些非常非常基础的内容。但是,它所涉及的基础技术显然有好几个,如果缺乏对图像处理理论的系统认识,你可能会感觉事倍功半。因为所有的地方好像都是沟沟坎坎。

关于课程——

在这个阶段其实对于数学的要求并不高,你甚至可以从一些感性的角度去形象化的理解图像处理中很多内容(但不包括频域处理方面的内容)。具体到学习的建议,如果有条件(例如你还在高校里读书)你最好能选一门图像处理方面的课程,系统地完整的地去学习一下。这显然是入门的最好办法。如此一来,在建立一个完整的、系统的认知上相当有帮助。如果你没办法在学校里上一门这样的课,网上的一些公开课也可以试试。但现在中文MOOC上还没有这方面的优质课程推荐。英文的课程则有很多,例如美国加州伦斯勒理工学院Rich教授的数字图像处理公开课——https://www.youtube.com/channel/UCaiJlKxXamoODQtlx486qJA?spfreload=10。

关于教材——

显然,只听课其实还不太够,如果能一并读一本书就最好了。其实不用参考很多书,只要一本,你能从头读到尾就很好了。如果你没有条件去上一门课,那读一本来完整的自学一下就更有必要了。这个阶段,去网上到处找博客、看帖子是不行的。因为你特别需要在这个阶段对这门学问建立一个系统的完整的知识体系。东一块、西一块的胡拼乱凑无疑是坑你自己,你的知识体系就像一个气泡,可能看起来很大,但是又脆弱的不堪一击。

现在很多学校采用冈萨雷斯的《数字图像处理》一书作为教材。这是一本非常非常经典的著作。但是我必须要提醒读者:

1)这是一本专门为Electronic Engineering专业学生所写的书。它需要有信号与系统、数字信号处理这两门课作为基础。如果你没有这两门课的基础,你读这本书要么是看热闹,要么就是看不懂。

下面是冈书中的一张插图。对于EE的学生来说,这当然不是问题。但是如果没有我说的那两门课的基础,其实你很难把握其中的精髓。H和h,一个大小一个小写,冈书中有的地方用H,有的地方用h,这都是有很深刻用意的。原作者并没有特别说明它们二者的区别,因为他已经默认你应该知道二者是不同的。事实上,它们一个表示频域信号,一个表示时域信号,这也导致有时候运算是卷积,有时候运算是乘法(当然这跟卷积定理有关)。所以我并不太建议那些没有这方面基础的学生在自学的时候读这本书。

 

2)冈萨雷斯教授的《数字图像处理》第一版是在1977年出版的,到现在已经快40年了;现在国内广泛使用的第二版是2002年出版的(第三版是2007年但是其实二者差异并不大),到现在也有20年左右的时间了。事实上,冈萨雷斯教授退休也有快30年了。所以这本书的内容已经偏于陈旧。数字图像处理这个领域的发展绝对是日新月异,突飞猛进的。特别在最近二三十年里,很多新思路,新方法不断涌现。如果你看了我前面推荐的Rich教授的公开课(这也是当前美国大学正在教学的内容),你一下子就会发现,原来我们的教育还停留在改革开放之前外国的水平上。这其实特别可怕。所以我觉得冈萨雷斯教授的《数字图像处理》作为学习过程中的一个补充还是不错的,但是如果把它作为主参考,那真的就是:国外都洋枪洋炮了,我们还在大刀长矛。

 

那么现在问题来了,对于图像处理学习者而言到底看什么书好呢?我的意见是你可以选择下面两本书中的任何一本《数字图像处理原理与实践(Matlab版)》,以及《数字图像处理:技术详解与Visual C++实践》,当然选择的标准之一就是到底你更擅长使用MATLAB还是C++。

   

 

 

 

2)对于中级水平者

 

纸上得来终觉浅,绝知此事要躬行。对于一个具有一定基础的,想更进一步的中级水平的人来说,这个阶段最重要的就是增强动手实践的能力。

还是说《天龙八部》里面的一个角色——口述武功、叹为观止的王语嫣。王语嫣的脑袋里都是武功秘籍,但问题是她从来都没练过一招一式。结果是,然并卵。所以光说不练肯定不灵啊。特别是,如果你将来想从事这个行业,结果一点代码都不会写,那几乎是不可想象的。学习阶段,最常被用来进行算法开发的工具是Matlab和OpenCV。你可以把这两个东西都理解为一个相当完善的库。当然,在工业中C++用得更多,所以Matlab的应用还是很有限的。前面我们讲到,图像处理研究内容其实包括:图像的获取和编解码,但使用Matlab和OpenCV就会掩盖这部分内容的细节。你当然永远不会知道,JPEG文件到底是如何被解码的。

如果你的应用永远都不会涉及这些话题,那么你一直用Matlab和OpenCV当然无所谓。例如你的研究领域是SIFT、SURF这种特征匹配,可以不必理会编解码方面的内容。但是如果你的研究话题是降噪或者压缩,可能你就绕不开这些内容。最开始学的时候,如果能把这部分内容也自己写写,可能会加深你的理解。以后做高级应用开发时,再调用那些库。所以具体用什么,要不要自己写,是要视你所处的阶段和自己的实际情况而定的。以我个人的经验,在我自学的时候,我就动手写了Magic House,我觉得这个过程为我奠定了一个非常夯实的基础,对于我后续的深入研究很有帮助。

 

下面这个文中,我给出了一些这方面的资源,代码多多,很值得参考学习:图像处理与机器视觉网络资源收罗

http://blog.csdn.net/baimafujinji/article/details/32332079

 

3)对于高级进阶者

 

到了这个程度的读者,编程实现之类的基本功应该不在话下。但是要往深,往高去学习、研究和开发图像处理应用,你最需要的内容就变成了数学。这个是拦在很多处于这个阶段的人面前的一大难题。如果你的专业是应用数学,当然你不会感觉有问题。但如果是其他专业背景的人就会越发感觉痛苦。

如果你的图像处理是不涉及机器学习内容的,例如用Poisson方程来做图像融合,那你就要有PDE数值解方面的知识;如果你要研究KAZE特征,你就必须要知道AOS方面的内容。如果你研究TV降噪,你又要知道泛函分析中的BV空间内容……这些词你可能很多都没听过。总的来说,这块需要的内容包括:复变函数、泛函分析、偏微分方程、变分法、数学物理方法……

如果你要涉足机器视觉方法的内容,一些机器学习和数据挖掘方法的内容就不可或缺。而这部分内容同样需要很强大的数学基础,例如最大似然方法、梯度下降法、欧拉-拉格朗日方程、最小二乘估计、凸函数与詹森不等式……

当然,走到这一步,你也已经脱胎换骨,从小白到大神啦!路漫漫其修远兮,吾将上下而求索。

 

(全文完)

 

 

2019-01-27 11:25:26 qq_27131611 阅读数 420
  • 互联网产品经理小白入门必修课

    以培训产品经理为目标,通过课程学习,对行业及产品经理岗位有基础认知,了解一个合格产品经理应该具备的能力和素质,掌握基础的工具,能够完成简单的原型制作,学习者达到初级到入门。

    8252 人正在学习 去看看 邓轰轰

基于Qt Creator 的Windows下数字图像处理软件[栏目]

前言

之前说准备转行软件开发,准备从C++的学习开始,恰好这学期的数字图像处理需要做一个项目,所以决定用QT C++来完成此次的项目设计,由于前期时间关系,没有及时更新,现在项目基本完成,准备写一个栏目的文章来与和我一样自学的小白分享一些Qt Creator、C++的知识,对这个项目进行总结的同时也希望能让看到这个栏目博客的朋友少走一些弯路。
在后面的项目介绍中会对使用到的一些控件以及C++语法做详细的解释,同时同步更新相对应的完整工程文件。

设计过程

设计过程在后面连载的博客中按逻辑功能讲解,下一篇:Qt C++:综合数字图像处理平台–登录界面设计。
请期待…

完整项目展示

经过大半个学期的努力,现学现用,总算撸出来了一个相对完善的综合数字图像处理平台(至于为什么是教学模块,后面再说),界面设计耗费很多精力,毕竟小白,对控件使用不熟悉。
话不多说,直接上图。

2018-05-12 19:30:14 qq_15262755 阅读数 14637
  • 互联网产品经理小白入门必修课

    以培训产品经理为目标,通过课程学习,对行业及产品经理岗位有基础认知,了解一个合格产品经理应该具备的能力和素质,掌握基础的工具,能够完成简单的原型制作,学习者达到初级到入门。

    8252 人正在学习 去看看 邓轰轰

主要参考《数字图像处理 原理与实践(matlab版)》一书

1、腐蚀

腐蚀在数学形态学运算中的作用是消除物体的边界点。在数字图像处理中,对于确定的结构元素,通过腐蚀运算可以消除小于结构元素的点。同时,若一个目标区域中含有细小的连接部分,那么通过笃实处理可以对区域进行分割。

matlab实现中,需要用到imerode()和strel()。

SE=strel(shape,parameters) //参数shape指定了结构元素的形状,parameter指定了输入shape相关的参数

I_result=imerode(I,SE)

shape的取值

 

arbitrary或空  自定义结构元素
disk       圆形
square 正方形
rectangle   长方形
line    线型
pair 包含2个点的结构元素
diamond 菱形
octagon    八角形


matlab代码:

clear;
I=imread('D:\Desktop\TEST.jpg');
SE=strel('disk',10);
im=imerode(I,SE);
figure,imshow(im),title('after erode');

2、膨胀

膨胀中以最大值来判断模板区域内原始图像到底是置于1还是置于0。到对于二值图像,用特定结构的模板去遍历图像上上每一个位置,如果模板特定结构所在位置有一个点为1,则图像上对应特定结构的位置都是1 。对于灰度图像,则是将取1的位置赋值以特定结构重合部位的灰度值的最大值。对于彩色图像则是对三种颜色分量分别进行膨胀处理。

其和腐蚀的最小值相反,在实现中同样适用到strel()函数,而真正执行的则是imdilate函数。

matlab代码

clear;
I=imread('D:\Documents\Desktop\TEST.jpg');
SE=strel('disk',10);
im=imdilate(I,SE);
figure,imshow(im),title('after erode');

 

图像的背景色对处理的结果影响。个人觉得在白底的时候白色是作为1的填充颜色,毕竟白色是FFFFFF,而黑色是000000,膨胀的时候是取最大值,腐蚀的时候是取最小值,所以会有白底和黑底差异较大的结果。

3、腐蚀和膨胀的关系

设目标图像为A,结构元素为S,用A-S表示对A进行腐蚀运算,用A+S表示对A进行膨胀预算。经推导可得:

(1)对偶性

(2)单调性

(3)递减(增)性

(4)交换律

(5)结合律

(6)平移不变性

(7)各种集合运算

4、腐蚀和膨胀的应用

(1)边界的提取

边界的提取是通过对目标图像进行腐蚀或膨胀处理,比较结果图像和原图像的差别来实现的。

内边界的提取利用图像的腐蚀处理得到原图像的一个收缩,再将收缩结果和目标图像进行异或运算。

外边界的提取对目标图像进行膨胀处理,然后利用膨胀结果与原目标图像进行异或运算。

提取图片内外边界的MATLAB代码

clear;
I=imread('D:\Documents\Desktop\boundary.jpg');
SE=strel('disk',10);
imd=imdilate(I,SE);
ime=imerode(I,SE);
id=imd-I;%计算外边界
ie=I-ime;%计算内边界
subplot(131),imshow(I),title('original image');
subplot(132),imshow(id),title('Outer boundary');
subplot(133),imshow(ie),title('Inner boundary');
figure(2)
subplot(131),imshow(I),title('original image');
subplot(132),imshow(imd),title('膨胀');
subplot(133),imshow(ime),title(' 腐蚀');

 

运行结果

 

5、开运算和闭运算

开运算:A○S=(A-S)+S (即对目标图像先腐蚀再膨胀)

闭运算:A●S=(A+S)-S(即对目标图像先膨胀再腐蚀)

图像的开运算常常用来对木笔哦啊图像进行消噪处理,同时,图像的开运算可以选择性地保留目标图像中符合结构原色几何性质的部分,而过滤掉相对结构元素而言残损的部分。

图像的闭运算常常用来对目标图像分开的区域进行连接及对图像中细小缝隙进行填补,通过适当地选择结构元素,图像的闭运算可以令图像的填补结果具有一点的几何特征,适当地对图像进行闭运算有时可以使图像变得更加清晰连贯,同时可以避免原图像中线条加粗。

matlab代码

clear;
I=imread('D:\Documents\Desktop\kakurablack.jpg');


SE=strel('disk',5);%定义结构元素的形状,圆形-半径5


Iop=imopen(I,SE);%开运算函数,可以直接进行开运算
Icl=imclose(I,SE);%闭运算函数,可以直接进行闭运算
imd=imdilate(I,SE);%只进行膨胀
ime=imerode(I,SE);%只进行腐蚀
imebi=imdilate(imerode(I,SE),SE);%闭运算,先膨胀再腐蚀
imekai=imerode(imdilate(I,SE),SE);%开运算,先腐蚀再膨胀


subplot(241),imshow(I),title('原图');
subplot(242),imshow(ime),title('只腐蚀');
subplot(246),imshow(imd),title('只膨胀');
subplot(245),imshow(I),title('原图');
subplot(243),imshow(Iop),title('开运算函数');
subplot(247),imshow(Icl),title('闭运算函数');
subplot(244),imshow(imekai),title('开运算--先腐蚀再膨胀');
subplot(248),imshow(imebi),title('闭运算--先膨胀再腐蚀');

 

 

白底运行结果

黑底运算结果

6、开运算和闭运算的性质

(1)对偶性

(2)扩展性(收缩性)

(3)单调性

(4)平移不变性

(5)等幂性:在利用开/闭运算进行处理是,处理结果不会因为重复操作而改变。

7、击中/不击中运算

bwhitmiss函数进行的击中击不中运算只能对二值化后的图像进行操作

clear;
I=imread('D:\Documents\Desktop\kakura.bmp');
I2=rgb2gray(I);
thresh = graythresh(I2);     %自动确定二值化阈值;
I3 =  imbinarize(I2,thresh);       %对图像自动二值化即可。
shape1=[0 0 1 0 
       0 0 0 1 ];%自己定义的结构元素1
shape2=[ 0 1 1 0 0
        0 1 1 0 0];%自己定义的结构元素2
imhit=bwhitmiss(I3,shape1,shape2);
    
    SE1=strel('rectangle',[1,3]);%自动生成结构元素长方形
    SE2=strel('disk',5);%自动生成结构元素圆形
    imhit2=bwhitmiss(I3,SE1,SE2);

subplot(221),imshow(I),title('原图');
subplot(222),imshow(imhit),title('击中击不中运算');
subplot(223),imshow(I2),title('灰度图');
subplot(224),imshow(I3),title('二值化');

 

运行结果如下

 

8、图像的细化处理

图像的细化处理是指在保留原图像几何形状的前提下,尽量减少图像所包含的信息量。图像细化的结果被形象的称为图像的骨架。

图像的细化操作实际上是一个逐渐腐蚀的过程,每次从图像的边缘腐蚀掉一个像素,直到不能继续腐蚀位置。

算法的关键是如何在每次腐蚀的过程中判断像素点是否可以清楚。根据不同的需要,可以有不同的准则,基本的两条准则是:①图像的细化不能缩短图像骨架的长度

②细化不能讲图像分解成不同部分

这两条准则在判断是可以总结为一下两点:

①计算当前像素领域内8个方向的可见像素数目,如果少于2个像素,则删除此像素会缩短图像骨架的长度;若多余6个像素,则删除此像素会改变图像骨架的几何形状

②计算大年像素周围领域内的区域数目,如果多余1个,那么删除中信像素会将目标图像分解成不同部分。

与前面的实例不同的是matlab没有直接提供一个专门的函数来实现图像的细化,而是通过一个通用的形态学处理函数bwmorph()来完成,该函数用以实现对二值图像进行一般数学形态学运算的操作。

clear;
I=imread('D:\Documents\Desktop\kakura.bmp');
I2=rgb2gray(I);
thresh = graythresh(I2);     %自动确定二值化阈值;
I3 =  imbinarize(I2,thresh);       %对图像自动二值化即可
img=bwmorph(I3,'thin',inf);
subplot(121),imshow(I),title('原图');
subplot(122),imshow(img),title('细化');

函数bwmorph(image,p,n)的三个参数,第一个image输入的图像,第二个p代表不同的操作方式,第三个n执行操作的次数

①其中image一定是二值图像

②n可以是Inf,即可运行无穷次,直到图像不再发生变化;n也可以缺省,这是主要有p的类型决定;当然可以自己指定具体的操作次数

③p的具体操作见下表

2018-05-23 08:53:58 qq_15262755 阅读数 5805
  • 互联网产品经理小白入门必修课

    以培训产品经理为目标,通过课程学习,对行业及产品经理岗位有基础认知,了解一个合格产品经理应该具备的能力和素质,掌握基础的工具,能够完成简单的原型制作,学习者达到初级到入门。

    8252 人正在学习 去看看 邓轰轰

主要参考《数字图像处理 原理与实践(matlab版)》一书

图像分割就是把图像划分成若干个特定的、具有独特性质的取悦,并提取其中感兴趣目标的技术和过程。

1、霍夫(Hough)变换

霍夫变换提供了一种将图像像素信息按照坐标映射到参数空间的方法。在网上可以搜到很多很详细的解释,小白就不讲了。

其核心思想书上的概括是:

1)确定要识别的曲线解析式集,即在一定精度上枚举带参数的解析式中所有参数的可能取值。

2)为解析式集合中的每个元素构造计数器。

3)遍历图像中的有效像素,并将没有有效像素的坐标一次代入解析式集中的每个元素,若解析式成立,则将改解析式对应的计数器加1.

4)设定阈值t,对于计数器值大于t的解析式,可认为其对应的曲线被识别。

clear
i=imread('D:\Documents\Desktop\example1.jpg');
ig=rgb2gray(i);
bw=edge(ig,'canny');%进行canny边缘检测

[H,T,R]=hough(bw,'RhoResolution',0.5,'ThetaResolution',0.5);%对进行边缘检测后的二值图进行霍夫变换
figure(1),imshow(imadjust(mat2gray(H)),'XData',T,'YData',R,'InitialMagnification','fit');%显示霍夫变换后的边缘图
xlabel('\theta'),ylabel('\rho');
axis on; axis normal;hold on;
colormap(hot);
peaks=houghpeaks(H,15);
figure(2),imshow(bw);
hold on;%hold on是当前轴及图像保持而不被刷新,准备接受此后将绘制的图形,多图共存
lines=houghlines(bw,T,R,peaks,'FillGap',25,'MinLength',15);

max_len=0;
for k=1:length(lines)
    xy=[lines(k).point1;lines(k).point2];
    plot(xy(:,1),xy(:,2),'LineWidth',3,'Color','b');
    plot(xy(1,1),xy(1,2),'x','LineWidth',3,'Color','yellow');
    plot(xy(2,1),xy(2,2),'x','LineWidth',3,'Color','red');
    
    len=norm(lines(k).point1-lines(k).point2);
    if (len > max_len)
        max_len=len;
        xy_long=xy;
    end
end



没有更多推荐了,返回首页