首页 > 代码库 > 【图像处理】第一次实验
【图像处理】第一次实验
1、任务说明
打开一幅图像,进行直方图均衡。将灰度线性变化,将灰度拉伸。
2、算法原理
1) 图像灰度化
在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫做灰度值,灰度范围为0-255。一般有四种方法对彩色进行灰度化,分别为:
分量法,最大值法,平均值法和加权平均法。本实验中采用平均值法,即
2) 直方图均衡
直方图表示数字图像中每一个灰度级与其出现频率间的统计关系。设有某一个灰度等级,属于该灰度等级的像素个数为nk,图像总像素个数为n,则直方图的定义为
图像的直方图反映了图像的灰度范围、灰度分布、图像的平均亮度等。
直方图均衡化也叫直方图均匀化,其目的是使所有灰度级出现的相对频率表相同,此时图像的熵最大,图像所包含的信息量最大。
本实验处理在离散情况下的直方图修正。其中第k个灰度级出现的概率为:
进行均匀化处理的变换函数为:
由新rk得到均衡化处理后的直方图。
3) 线性变化
设输入图像的的灰度范围为[a,b],希望经过变换后的输出图像的灰度范围变化为[c,d],则变换函数T的表达式可以表示为
根据不同的线性变换的斜率和截距,可以达到对图像不同的处理效果。当斜率大于1时,可以增加图像的对比度;当斜率在0与1之间时,
图像的对比度和整体效果都被削弱,灰度会被集中在一段区域上,灰度取值变窄,使图片趋于灰色。当斜率为负时,源图像较亮的区域变暗,
较暗的区域变量,可以实现反色效果。而当截距为正时,图像的亮度将会增加;截距为负时,图像的亮度将会降低。
4) 灰度拉伸(分段线性变化)
为了突出感兴趣的目标或灰度区间,相对一致不感兴趣的灰度区间,可以采用分段线性变换。本实验采用常用的三段线性变换方法。
具体算法如下:
3、算法实现
1) 图像灰度化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public void turnGray() { for ( int i=minx;i<width;i++) { for ( int j=miny;j<height;j++) { int pixel=bi.getRGB(i,j); //获得8位的RGB值 int a = (pixel >> 24 ) & 0xff ; //提取前两位透明度 int r = (pixel >> 16 ) & 0xff ; //提取次两位,R值 int g = (pixel >> 8 ) & 0xff ; //提取再次两位,G值 int b = pixel & 0xff ; //提取最后两位,B值 int gray=(r+g+b)/ 3 ; //计算平均值,得到像素灰度 //根据灰度得到完整8位RGB值 pixel= (a<< 24 )|(gray<< 16 )|(gray<< 8 )|gray; //将新的RGB值赋给像素点 bi.setRGB(i, j,pixel); } } //输出图像 try { ImageIO.write(bi, "jpg" , new File( "D://gray.jpg" )); } catch (IOException e) { e.printStackTrace(); } } |
2) 直方图均衡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public void histEqua() { int [] gray = new int [sum]; //保存初始灰度值 int [] newgray = new int [sum]; //保存新灰度值 int [] oldgrayscale = new int [ 256 ]; //保存灰度累加值 double [] grayscale = new double [ 256 ]; double [] cumulative = new double [ 256 ]; //统计所有像素中各灰度值出现的次数 for ( int i=minx;i<width;i++){ for ( int j=miny;j<height;j++){ int pixel=bi.getRGB(i, j); gray[height*i+j] = (pixel & 0xff ); oldgrayscale[gray[height*i+j]]++; } } for ( int i= 0 ;i< 256 ;i++){ //计算原直方图中各灰度值出现的频率 grayscale[i] = (( double )oldgrayscale[i])/sum; for ( int j= 0 ;j<=i;j++){ //计算累加后的直方图 cumulative[i] += grayscale[j]; } //得到新的映射关系 cumulative[i] = ( int )(cumulative[i]* 256 ); } BufferedImage hist_equa = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //根据累加数组得到新的像素灰度 for ( int i=minx;i<width;i++){ for ( int j=miny;j<height;j++){ newgray[height*i+j] = ( int )cumulative[gray[height*i+j]]; int pixel = (newgray[height*i+j])|(newgray[height*i+j]<< 8 )|(newgray[height*i+j]<< 16 ); hist_equa.setRGB(i, j, pixel); } } //输出图像 try { ImageIO.write(hist_equa, "jpg" , new File( "D://histEqua.jpg" )); } catch (IOException e) { e.printStackTrace(); } } |
3) 线性变换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public void linTrans() { //得到线性变换函数的斜率和截距 double slope; double intercept; Scanner in = new Scanner(System.in); System.out.println( "输入线性变换斜率:" ); slope=in.nextDouble(); System.out.println( "输入线性变换截距:" ); intercept=in.nextDouble(); BufferedImage lt = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR); for ( int i=minx;i<width;i++) { for ( int j=miny;j<height;j++) { //提取灰度值 int pixel = bi.getRGB(i, j); pixel = pixel & 0xff ; //进行线性变换 pixel = ( int )(pixel*slope + intercept); //对超出边界的值进行处理 if (pixel< 0 ) pixel= 0 ; if (pixel> 255 ) pixel= 255 ; //恢复为RGB值 pixel = (pixel<< 16 )|(pixel<< 8 )|pixel; lt.setRGB(i, j, pixel); } } //输出图像 try { ImageIO.write(lt, "jpg" , new File( "D://linTrans.jpg" )); } catch (IOException e) { e.printStackTrace(); } } |
4) 灰度拉伸
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | public void linStr() { int x1,x2,y1,y2; double k1,k2,b1,b2,k3,b3; //读入线性变换两份转折点的坐标 Scanner in = new Scanner(System.in); System.out.println( "输入灰度拉伸第一个点的坐标,以空格分开:" ); x1 = in.nextInt(); y1 = in.nextInt(); System.out.println( "输入灰度拉伸第二个点的坐标,以空格分开:" ); x2 = in.nextInt(); y2 = in.nextInt(); in.close(); //计算三段线性变换各阶段的斜率与截距 k1 = y1/x1; b1 = 0 ; k2 = (y2-y1)/(x2-x1); b2 = y1-k2*x1; k3 = ( 255 -y2)/( 255 -x2); b3 = y2-k3*x2; BufferedImage ls = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR); for ( int i=minx;i<width;i++) { for ( int j=miny;j<height;j++) { //提取像素点灰度值 int pixel = bi.getRGB(i, j); pixel = pixel & 0xff ; //分段进行线性变化 if (pixel<x1) pixel = ( int )(pixel*k1 + b1); else if (pixel>=x2) pixel = ( int )(pixel*k3 + b3); else pixel = ( int )(pixel*k2 + b2); //对于超出边界的值进行处理 if (pixel< 0 ) pixel= 0 ; if (pixel> 255 ) pixel= 255 ; pixel = (pixel<< 16 )|(pixel<< 8 )|pixel; ls.setRGB(i, j, pixel); } } //输出图像 try { ImageIO.write(ls, "jpg" , new File( "D://linStr.jpg" )); } catch (IOException e) { e.printStackTrace(); } } private BufferedImage bi= null ; private int width; private int height; private int minx; private int miny; private int sum; } |
4、实验
源图像 灰度图像
直方图均衡化 (-1,255)线性变换,相当于反色
灰度拉伸,某些像素得到凸显