前言:灰度处理相较于双线性内插值法要容易理解很多。
1. 灰度处理
介绍:
一幅具有256个灰度级([0,255])的图像,如果量化2level则保留像素值0和255,即整张数图的像素值只能取0和255这两个值其中之一,并且离哪个值比较近,就取哪个。比如你原来的像素是90,我们已知0和255的中间值是128,那么90应该改为0。根据这种思路,遍历所有像素,一一将其改成最贴近的像素即可。
####思路:
怎么具体改成最贴近的像素呢,这其实是一道算法题,比如2level是保留像素值0和255,4level是0,85,170和255,可以发现每个level的间隔区间都是255/(level-1)取整。比如level4的间隔255/(4-1)=85,所以第0层是85*0,第1层是85*1,第2层是85*2,第3层是85*3。我们要实现一种算法使得某个0-255的值能找到其所归属的层,然后改为该层对应的像素。比如我们的像素是90,那么很容易想到要先算出90该去第几层,可以用90/间隔85得到1.06多的一个浮点数,如果是0-0.5则去第0层,0.5-1.5则去第1层,1.5-2.5则去第2层,2.5-3.5则去第三层,注意:这里为什么要有到3.5呢?按道理来说最高像素值是255,255/85不可能超过3,但是还是有特殊情况的,比如当level为8时,间隔为36,那么255/36为7.083,所以超过了7,至于有没有可能超过7.5我没去试过,但是没所谓的,我们给所求的像素值加个255的上限即可。根据这个规律,我们得出具体操作步骤。
操作:
先用(像素值/间隔)得出浮点数,⌊ 像素值/间隔 ⌋得出浮点数的整数部分,再用该浮点数-浮点数的整数部分得出浮点数的小数部分,将小数部分与0.5比较,如果超过了则整数部分+1,没超过则不变,最后整数部分乘以间隔即为所求像素值
2. 代码
java实现:
import java.awt.*;
import java.awt.Graphics2D;
import java.awt.image.ColorModel;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageReader {
//原图、宽、高、RGB矩阵、图片路径
private BufferedImage bufferedImage = null;
private int width;
private int height;
private double[][][] sourceRGB;
private String filePath = "./hw1_input/20.png";
ColorModel cm = ColorModel.getRGBdefault();
ImageReader() {
//读取图片
try {
bufferedImage = ImageIO.read(new File(filePath));
} catch (IOException e) {
e.printStackTrace();
}
width = bufferedImage.getWidth();
height = bufferedImage.getHeight();
//量化
quantize(128);
quantize(32);
quantize(8);
quantize(4);
quantize(2);
}
//量化
public void quantize(int level) {
BufferedImage buffImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
//注意,读进来彩色图像用TYPE_INT_ARGB(三通道),灰度图用TYPE_BYTE_GRAY(单通道),灰度图用TYPE_INT_ARGB会变亮
// 将图像画到buffImage中
Graphics2D bGr = buffImage.createGraphics();
bGr.drawImage(bufferedImage, 0, 0, width, height, null);
bGr.dispose();
//设置每个区间段
int gap = (int) (256 / (level-1));
//存储量化后的RGB值
int pix[] = new int[width * height];
bufferedImage.getRGB(0, 0, width, height, pix, 0, width);
int r, g, b, temp;
double doutemp;
for(int i = 0; i < width * height; i++) {
r = cm.getRed(pix[i]);
temp = r / gap;
doutemp = (double)r/gap - temp;
if (doutemp - 0.5 > 0) {
temp++;
}
r = temp*gap > 255 ? 255 : temp*gap;
g = cm.getGreen(pix[i]);
temp = g / gap;
doutemp = (double)g/gap - temp;
if (doutemp - 0.5 > 0) {
temp++;
}
g = temp*gap > 255 ? 255 : temp*gap;
b = cm.getBlue(pix[i]);
temp = b / gap;
doutemp = (double)b/gap - temp;
if (doutemp - 0.5 > 0) {
temp++;
}
b = temp*gap > 255 ? 255 : temp*gap;
pix[i] = new Color(r, g, b).getRGB();
}
//把图像设置为新的RGB值
buffImage.setRGB(0, 0, width, height, pix, 0, width);
//将图片输出为png格式
File output= new File("./targetImg/level_" + Integer.toString(level) + ".png");
try {
ImageIO.write(buffImage, "png", output);
} catch(IOException e) {
return;
}
}
}
运行:再随便写一个类,main函数中new一下ImageReader即可。
matlab实现:
function output_img = quantize(input_img, level)
%Input - input_img is a two-dimensional matrices storing image
% - level is an integer in [1; 256] defining the number of gray levels of output
%Output - output_img is the same as input_img
imshow(input_img); %显示原图
img = imread(input_img); %读取输入图片的数据
[h,w] = size(img); %获取行和列,即原图的高度和宽度
output_img = zeros(h, w); %初始化
d = 255 / (level - 1)
for i = 1 : h
for j = 1 : w
output_img(i, j) = round(round(img(i, j) / d) * d);
end
end
imwrite(uint8(output_img), 'output_img.png');
figure,imshow(uint8(output_img));
end
运行:quantize(‘C:\Users\Administrator\Desktop\20.png’, 128);