导航索引帖
前置文章,课设第二篇
上一章我们姑且完成了图像打开的功能,这一章开始将开始对图像处理环节开始进行制作。
一张彩色图像中,每个像素点的颜色由R、G、B三个值来决定,每个值都从0-255分布,能组合出255255255种颜色。
而灰度图像的RGB值为三个相同的数值,其一个像素点的变化范围为255种,所以在数字图像处理种一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。图像的灰度化处理可用两种方法来实现。
求出每个像素点的R、G、B三个分量的平均值,然后将这个平均值赋予给这个像素的三个分量。
根据YUV的颜色空间中,Y的分量的物理意义是点的亮度,由该值反映亮度等级,根据RGB和YUV颜色空间的变化关系可建立亮度Y与R、G、B三个颜色分量的对应:Y=0.3R+ 0.59G +0.11B,以这个亮度值表达图像的灰度值。
出于方便,这里我们直接采用方法一即可,即Gray=(R+G+B)/3;
//灰度化
QImage MainWindow::gray(QImage image){
QImage newImage =image.convertToFormat(QImage::Format_ARGB32);
QColor oldColor;
for(int y = 0; y < newImage.height(); y++)
{
for(int x = 0; x < newImage.width(); x++)
{
oldColor = QColor(image.pixel(x,y));
int average = (oldColor.red() + oldColor.green() + oldColor.blue()) / 3;
newImage.setPixel(x, y, qRgb(average, average, average));
}
}
return newImage;
}
灰度化的方法目的在于对目标图像的每一个像素点都进行灰度化处理,最终得出的图像即灰度化图像了。
//灰度化按钮
void MainWindow::on_GreyBtn_clicked()
{
if(srcDirPathList.isEmpty())
{
QMessageBox::information(this,tr("请先选择图片"),
tr("请先选择图片!"));
return;
}
else{
QImage image=QImage(srcDirPathList.at(imagenum));
QImage grayimage=gray(image);
ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(grayimage,ui->piclabel)));
}
}
再将灰度化的按钮功能实现,同样需要先验证当前是否有图片再进行灰度化处理,效果如下图。
既然有改变图像,就需要有显示原图,我们将显示原图的按钮也实现一下功能。
//显示原图按钮
void MainWindow::on_YuanTuBtn_clicked()
{
if(srcDirPathList.isEmpty())
{
QMessageBox::information(this,tr("请先选择图片"),
tr("请先选择图片!"));
return;
}
else{
QImage image=QImage(srcDirPathList.at(imagenum));
ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(image,ui->piclabel)));
}
}
这边的代码出现过很多次了,不再解释了。
二值化就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。我们首先需要将图片灰度化,再将灰度化后的每个值与我们设定的二值化调节值进行比对,大于调节值的直接变成黑色(255,255,255),小于调节值的则变为白色(0,0,0),即可获取二值化图像(阈值图像)。
这里我们需要添加一个用于调节二值化的调节条,QT提供了Qslider类,横向的叫做Horizontal Slider,纵向的叫做Vertical Slider。
我希望的效果为:任意改变调节条能显示出数字,任意改变LineEdit中数字则能改变调节条(0-255范围内)。
这块代码总体上结合上面的原理来看相对比较好理解,递归地进行取灰度,比对,改值。
//二值化
QImage MainWindow::TwoSide(QImage grayimage,int value){
QImage TwoSideImage =grayimage.convertToFormat(QImage::Format_ARGB32);
QColor oldColor;
int ts;
for(int y = 0; y < grayimage.height(); y++)
{
for(int x = 0; x < grayimage.width(); x++)
{
oldColor = QColor(grayimage.pixel(x,y));
ts = oldColor.red();
if(ts<value){
ts=0;
}else{
ts=255;
}
TwoSideImage.setPixel(x,y, qRgb(ts, ts, ts));
}
}
return TwoSideImage;
}
首先进行前者的功能设计。
找到TwoSidelSlider的属性maxmum设置为255,代表最大二值化值为255,minimum本来就是0,不需要调整改动。
在调节条的跳转槽中找到valueChanged(),即当调节条的数值变化,则进行代码运行。
//二值化调节条
void MainWindow::on_TwoSidelSlider_valueChanged(int value)
{
if(srcDirPathList.isEmpty()){
QMessageBox::information(this,tr("请先选择图片"),
tr("请先选择图片!"));
return;
}
else{
QImage image=QImage(srcDirPathList.at(imagenum));//读取当前图片
QImage grayimage=gray(image);//灰度化
QImage TwoSideImage=TwoSide(grayimage,value);//二值化
ui->TwoSideLineEdit->setText(QString::number(value));//改变文本框内值为二值化比对值
ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(TwoSideImage,ui->piclabel)));//显示二值化图像
}
}
代码比较简单,不用多说了吧。
其实写了调节条之后,文本框功能也很容易就能想到,这里就直接上代码了,有疑问的可以看看注释,还有其他疑问可以评论或者私信我一下。
//二值化文本框
void MainWindow::on_TwoSideLineEdit_textChanged(const QString &arg1)
{
if(srcDirPathList.isEmpty()){
QMessageBox::information(this,tr("请先选择图片"),
tr("请先选择图片!"));
return;
}
else{
int value=arg1.toInt();
if (value>=0 && value<=255)
{
QImage image=QImage(srcDirPathList.at(imagenum));
QImage grayimage=gray(image);
QImage TwoSideImage=TwoSide(grayimage,value);//都是和上面一样的
ui->TwoSidelSlider->setValue(value);//当文本框内数值改变时,动态变化调节条位置
ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(TwoSideImage,ui->piclabel)));
}
else
{
QMessageBox::information(this,tr("请输入正确数值"),
tr("请输入0-255!"));
return;
}
}
}
二值化部分功能就已经完成了,但这个时候发现,二值化按钮好像就没什么用了,那我们把它删除掉,界面上不留没有用的按钮。
二值化效果图如下,总的来说二值化这块难度也不大的,灰度化能完成的话二值化是顺势下去的。
使用白话的形式对滤波定义:对于一个像素点,使用其领域像素(可以包含自身x,也可不包含)的相关特性,计算出一个值,代替当前像素值。
3x3均值滤波,就是计算每个像素对应的3x3领域所有像素值的平均值,代替当前像素。
均值滤波的原理相对简单,公式表示为
即以当前像素点为中心,求窗口内所有灰度值的和,以其平均值作为中心像素新的灰度值。
g(x,y)为该邻域的中心像素,n跟系数模版大小有关,一般3*3邻域的模板,n取为9,如:
在实际处理过程中,需要考虑对于图像边界进行扩充操作,扩充为0或临近像素值。
由于本次课设时间相对来说并不宽裕,暂时不考虑优化算法提速,后续如果时间有空余则再做补充。
这块代码可能相对比较难理解,后续我会单独针对这块代码发一篇博客解释,链接也会贴在此处。当下姑且不谈,先用上这块代码去实现功能。
//均值滤波
QImage MainWindow::avg(QImage image)
{
int kernel [3][3] = {
{1,1,1},
{1,1,1},
{1,1,1}};
int sizeKernel = 3;
int sumKernel = 9;
QColor color;
for(int x = sizeKernel/2;x<image.width() - sizeKernel/2;x++)
{
for(int y= sizeKernel/2;y<image.height() - sizeKernel/2;y++)
{
int r = 0;
int g = 0;
int b = 0;
for(int i = -sizeKernel/2;i<=sizeKernel/2;i++)
{
for(int j = -sizeKernel/2;j<=sizeKernel/2;j++)
{
color = QColor(image.pixel(x+i,y+j));
r+=color.red()*kernel[sizeKernel/2+i][sizeKernel/2+j];
g+=color.green()*kernel[sizeKernel/2+i][sizeKernel/2+j];
b+=color.blue()*kernel[sizeKernel/2+i][sizeKernel/2+j];
}
}
r = qBound(0,r/sumKernel,255);
g = qBound(0,g/sumKernel,255);
b = qBound(0,b/sumKernel,255);
image.setPixel(x,y,qRgb( r,g,b));
}
}
return image;
}
均值滤波按钮的功能应该不用解释了吧。
//均值滤波按钮
void MainWindow::on_TXTBtn_clicked()
{ if(srcDirPathList.isEmpty())
{
QMessageBox::information(this,tr("请先选择图片"),
tr("请先选择图片!"));
return;
}
else{
QImage image=QImage(srcDirPathList.at(imagenum));
QImage avgimage=avg(image);
ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(avgimage,ui->piclabel)));
}
}
至此,本章所有内容都完成了,有疑问或者发现bug请尽快联系我。