这段时间我对Java进行图像处理,进行了学习。所谓图像处理,就是用Java先对图片的每个像素点进行循环遍历。然后对像素点进行操作,实现对整张图片进行图像处理的目的。
博主已经把自己的代码上传到自己的资源,大家需要自取。
一.解析原图
解析原图就是上面提到的对每个像素点进行遍历,然后用一个二维数组对像素点的RGB值进行进行保存,达到对RGB值更改的目的,整张图片就也会被更改。RGB值的百度百科定义如下;
解析原图的代码如下:
public void load() {
File file = new Filedemo().openFile();
if(file==null) {
return;
}
try {
//加载图片
BufferedImage buffer = ImageIO.read(file);
data = new int[buffer.getHeight()][buffer.getWidth()];
newdata = new int[buffer.getHeight()+2][buffer.getWidth()+2];
//获取图片数据
draw.buffer=buffer;
for(int i=0;i<buffer.getHeight();i++) {
for(int j=0;j<buffer.getWidth();j++) {
data[i][j]=buffer.getRGB(j, i);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
其中的
File file = new Filedemo().openFile()
这一行是我设置了一个文件打开器,file是我打开的图片文件,我用data来对图片信息储存,newdata是用来下面的卷积特效做准备。在其他的特效,如马赛克,老时光,底片,黑白等效果中不需要用到。
原图效果
在上面的加载过程完成后,我们选择的图像信息就存在了data数组里面,然后对数组再次进行遍历画点,便可以将原图绘出。
代码如下:
//原图
public void yuantu(Graphics g) {
for(int i=0;i<data.length;i++) {
for(int j=0;j<data[i].length;j++) {
int value=data[i][j];
Color color = new Color(data[i][j]);
bg.setColor(color);
bg.drawLine(j+120, i+80, j+120, i+80);
}
}
//绘制缓存到窗体上
g.drawImage(buffer, 0, 0, null);
}
其中buffer是我存在缓存的图片,如果不把图片存在缓存的话,图片就会一行一行的慢速加载,而先存在缓存里面再在画布g中显示出来的话,就会快速的显示出来。
如下图,是我用我的连连看开始画面的原图。
黑白效果
//黑白
public void BlackWhite(Graphics g) {
for(int i=0;i<data.length;i++) {
for(int j=0;j<data[i].length;j++) {
int value=data[i][j];
int red = (0x00ff0000&value)>>16;
int green = (0x0000ff00&value)>>8;
int blue = 0xff&value;
c =new Color(blue,blue,blue);
bg.setColor(c);
bg.drawLine(j+120, i+80, j+120, i+80);
//先画到缓存bg里面,然后再画的时候就直接出来了
}
}//绘制缓存到窗体上
g.drawImage(buffer, 0, 0, null);
}
黑白效果很简单,就是每个点的RGB值设为相同的。就会单点显示黑or白,然后整体就是黑白效果了。放一张效果图。
马赛克特效
马赛克特效就是把点变为一个个小矩形去填充,代码也比较容易,所以直接贴代码了。
代码中的画点就由画点变为填充矩形了。
bg.fillRect(j+120,i+80,20,20);
//马赛克
public void Mosaic(Graphics g) {
for(int i=0;i<data.length;i+=20) {
for(int j=0;j<data[i].length;j+=20) {
int value=data[i][j];
int red = (0x00ff0000&value)>>16;
int green = (0x0000ff00&value)>>8;
int blue = 0xff&value;
c =new Color(red,green,blue);
bg.setColor(c);
bg.fillRect(j+120,i+80,20,20);
}
}
//绘制缓存到窗体上
g.drawImage(buffer, 0, 0, null);
}
贴一张效果图
底片特效
底片的效果就是拿原图的rgb值被255减去就好了。代码也很简单,就直接贴代码与效果图了。
//底片
public void dipian(Graphics g) {
for(int i=0;i<data.length;i++) {
for(int j=0;j<data[i].length;j++) {
int value=data[i][j];
int red = 255-((0x00ff0000&value)>>16);
int green = 255-((0x0000ff00&value)>>8);
int blue = 255-(0xff&value);
c=new Color(red,green,blue);
bg.setColor(c);
bg.drawLine(j+120, i+80, j+120, i+80);
}
}
//绘制缓存到窗体上
g.drawImage(buffer, 0, 0, null);
}
效果图如下:
旧时光特效
旧时光特效就是在原图的基础上,让相片看上去有点怀旧的感觉。
//老时光
public void old(Graphics g) {
for(int i=0;i<data.length;i++) {
for(int j=0;j<data[i].length;j++) {
int value=data[i][j];
int red = (0x00ff0000&value)>>16;
int green = (0x0000ff00&value)>>8;
int blue = 0xff&value;
int fr = (int)colorBlend(noise(), (red * 0.393) + (green * 0.769) + (blue * 0.189), red);
int fg = (int)colorBlend(noise(), (red * 0.349) + (green * 0.686) + (blue * 0.168), green);
int fb = (int)colorBlend(noise(), (red * 0.272) + (green * 0.534) + (blue * 0.131), blue);
c =new Color(clamp(fr),clamp(fg),clamp(fb));
bg.setColor(c);
bg.drawLine(j+120, i+80, j+120, i+80);
//先画到缓存bg里面,然后再画的时候就直接出来了
}
}
//绘制缓存到窗体上
g.drawImage(buffer, 0, 0, null);
}
private double noise() {
return Math.random()*0.5 + 0.5;
}
private double colorBlend(double scale, double dest, double src) {
return (scale * dest + (1.0 - scale) * src);
}
private int clamp(int c)
{
return c > 255 ? 255 :( (c < 0) ? 0: c);
}
效果图如下:
图像卷积处理特效
在此例中,实现的图像卷积原理是拿一个3×3的矩阵对图片的每个像素点进行处理。而且要对每个像素点的RGB值单独处理。在本例中,我用的矩阵是
【-1,-1,-1】
【-1, 8 , -1】
【-1,-1,-1】
对图片进行处理,我将其存在了一个一维数组里面。改变里面的参数的话,得到的图形效果也不同。
代码如下
//图像卷积
public void juanji(Graphics g) {
int RGB[] = new int[9];
int k[] = { -1, -1, -1, -1, 8, -1, -1, -1, -1 };
for (int j = 1; j < data[0].length - 1; j++) {
for (int i = 1; i < data.length - 1; i++) {
RGB[0] = data[i - 1][j - 1];
RGB[1] = data[i][j - 1];
RGB[2] = data[i + 1][j - 1];
RGB[3] = data[i - 1][j];
RGB[4] = data[i][j];
RGB[5] = data[i + 1][j];
RGB[6] = data[i - 1][j + 1];
RGB[7] = data[i][j + 1];
RGB[8] = data[i][j + 1];
int R = 0;
int G = 0;
int B = 0;
for (int n = 0; n < 9; n++) {
R += (((0x00ff0000 & RGB[n]) >> 16) * k[n]);
G += (((0x0000ff00 & RGB[n]) >> 8) * k[n]);
B += ((0xff & RGB[n]) * k[n]);
}
if (R > 255)
R = 255;
if (G > 255)
G = 255;
if (B > 255)
B = 255;
if (R < 0)
R = 0;
if (G < 0)
G = 0;
if (B < 0)
B = 0;
c = new Color(R, G, B);
bg.setColor(c);
bg.drawLine(j+120, i+80, j+120, i+80);
}
}
g.drawImage(buffer, 0, 0, null);
}
图片效果如下:
在卷积的基础上再做删改就可以得到素描或者浮雕的效果了。
沙画特效
小伙伴们应该都看到过沙画,下面这种特效就是实现沙画的效果。
沙画的实现主要是对下落规则的实现。
将图片的像素点进行2x2的分组,然后总共有九种下落的规则。
在下面叙述中,黑点代表沙子。
代码如下
//时间沙画
public void TSpainting(Graphics g){
//数组color保存图像0,1信息
color = new int[buffer.getWidth()][buffer.getHeight()];
//将图像的黑白信息储存到 数组color中,黑为0,其他为1
for(int i=0;i<buffer.getHeight();i++)
for(int j=0;j<buffer.getWidth();j++)
{
int RGB = buffer.getRGB(j, i);
int R = (RGB>>16) & 0xff;
int G = (RGB>>8) & 0xff;
int B = RGB & 0xff;
int VAG = (int)(R+G+B)/3;
if(VAG<30)
color[j][i]=0;
else
color[j][i]=1;
}
//画n张图像,实现动态效果
for(int R=1;R<200;R++){
if(R%2!=0)
{
//从(0,0)取2*2卷积,对数组color进行变换
for(int i=0;i<buffer.getHeight()-2;i+=2)
for(int j=0;j<buffer.getWidth()-2;j+=2)
{
double p = Math.random();
if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=0;
}
else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=0;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)&&(p<=0.8)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
color[j][i]=1;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
color[j][i]=0;
color[j+1][i]=1;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
}
//根据变化之后的数组color进行绘图
BufferedImage image = new BufferedImage(buffer.getWidth(), buffer.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics bg = image.getGraphics();
for(int i=0;i<buffer.getHeight();i++)
for(int j=0;j<buffer.getWidth();j++)
{
if(color[j][i]==0)
bg.setColor(Color.black);
else if(color[j][i]==1)
bg.setColor(Color.white);
bg.drawLine(j+120, i+80, j+120, i+80);
}
g.drawImage(image, 0, 0, null);
}
else if(R%2==0)
{
//从(1,1)取2*2卷积,对数组color进行变换
for(int i=1;i<buffer.getHeight()-1;i+=2)
for(int j=1;j<buffer.getWidth()-1;j+=2)
{
double p = Math.random();
if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=0;
}
else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=0;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)&&(p<=0.8)){
color[j][i]=0;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
color[j][i]=1;
color[j+1][i]=0;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
color[j][i]=0;
color[j+1][i]=1;
color[j][i+1]=1;
color[j+1][i+1]=1;
}
}
//根据变化之后的数组color进行绘图
BufferedImage image = new BufferedImage(buffer.getWidth(), buffer.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics bg = image.getGraphics();
for(int i=0;i<buffer.getHeight();i++)
for(int j=0;j<buffer.getWidth();j++)
{
if(color[j][i]==0)
bg.setColor(Color.BLACK);
else if(color[j][i]==1)
bg.setColor(Color.WHITE);
bg.drawLine(j+120, i+80, j+120, i+80);
}
g.drawImage(image, 0, 0, null);
}
}
}
图片如下
摄像头
//摄像
public void cam(Graphics g) {
//获取摄像头
Webcam cam = Webcam.getDefault();
//设置摄像头的大小
cam.setViewSize(WebcamResolution.VGA.getSize());
//打开摄像头
cam.open();
//获取图像
for(int i=0;i<100;i++) {
// long start = System.currentTimeMillis();
BufferedImage buffer = cam.getImage();
ImgToArr(buffer);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//BlackWhite(g);
BlackWhite(g);
//System.out.println(System.currentTimeMillis()-start);
}
//关闭摄像头
cam.close();
}
//图片转数组
public void ImgToArr(BufferedImage img) {
data = new int[img.getHeight()][img.getWidth()];
for(int i=0;i<img.getHeight();i++) {
for(int j=0;j<img.getWidth();j++) {
data[i][j]=img.getRGB(j, i);
}
}
}
我会把我的代码上传到我的资源之中,有需要的小伙伴可以下载,里面包括调用摄像头,可以实现比如摄像头显示黑白效果或者底片啊旧时光效果等等。