前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >seamCarving

seamCarving

作者头像
luxuantao
发布2021-02-24 11:21:58
2850
发布2021-02-24 11:21:58
举报
文章被收录于专栏:Fdu弟中弟Fdu弟中弟

其实吧,问题求解课还是有点意思的。。

Seam Carving:以水平和垂直两种方式简单地压缩和拉伸图片,常用于一些图像处理软件,能够做到主要目标不失真。结果肖老师二话不多说就让我们自己写一个。。我哪会写什么图像压缩,网上一查全是java的代码,可我已经忘得差不多了。再查c++,结果c++要用到openCV,呵呵,我还是用java吧。可毕竟菜得扣脚(其实是懒),就拿来了同学的代码看了看,其实并不难,我就顺手补充了点注释。

代码如下:

代码语言:javascript
复制
import edu.princeton.cs.algs4.Picture;
import java.awt.*;
import java.util.*;

public class seamCarving {
	
    private int[][] colors;
    private int width;
    private int height;
    
    public seamCarving(Picture picture) {
        width=picture.width();
        height=picture.height();
        colors = new int[height][width];
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                colors[i][j] = picture.get(j, i).getRGB(); //普林斯顿大学把这个函数的参数定为先写col,后写row
            }
        }
    }
    
    public Picture picture() {
        Picture picture = new Picture(width,height);
        for (int i = 0; i <height; i++)
            for (int j = 0; j <width; j++) {
                Color color = new Color(colors[i][j]);
                picture.set(j, i, color);
            }
        return picture;
    }
  
    //能量函数
    public double energy(int x, int y) {
        if (x==0||x==height-1||y==0||y==width-1) {
            return 1000.0;
        }
        else {
            int dxRed = red(colors[x - 1][y]) -red(colors[x + 1][y]);
            int dxGreen = green(colors[x - 1][y]) -green(colors[x + 1][y]);
            int dxBlue = blue(colors[x - 1][y]) -blue(colors[x + 1][y]);
            int dyRed = red(colors[x][y - 1]) - red(colors[x][y + 1]);
            int dyGreen = green(colors[x][y - 1]) - green(colors[x][y + 1]);
            int dyBlue = blue(colors[x][y - 1]) - blue(colors[x][y + 1]);
            return Math.sqrt(Math.pow(dxRed, 2) + Math.pow(dxBlue, 2) + Math.pow(dxGreen, 2) + Math.pow(dyRed, 2) + Math.pow(dyBlue, 2) + Math.pow(dyGreen, 2));
        }
    }
    
    public int[] findVerticalSeam() {
        double[][] dist=new double[height][width];
        int[][] node=new int[height][width];
        int[] seam=new int[height];
        //初始化
        for(int i=0;i<height;i++) { 
        	for(int j=0;j<width;j++) {
        		if(i==0) {
        			dist[i][j]=0.0;
        		} else {
        			dist[i][j]=Double.POSITIVE_INFINITY;
        		}
        	}
        }
        for(int i=1;i<height;i++) {
        	for(int j=0;j<width;j++) {
        		for(int k=-1;k<=1;k++) {
        			if(j+k<0||j+k>=width) continue;
        			if(dist[i][j]>(dist[i-1][j+k]+energy(i,j))) {
        				dist[i][j]=(dist[i-1][j+k]+energy(i,j));
        				node[i][j]=j+k; //记录是从哪个点过来的
        			}
        		}
        	}
        }
        int index=0;
        //找到最后一行中路径总和最短的那一个点
        for(int j=1;j<width;j++) {
        	if(dist[height-1][j]<dist[height-1][index])	{
        		index=j;
        	}
        }
        //向上回溯
        for(int i=height-1;i>=0;i--) {
        	seam[i]=index;
        	index=node[i][index];
        }
        return seam; //返回这条路径的下标数组
    }
    
    public void removeVerticalSeam(int[] seam) {
        int[][] a = new int[height][width-1];
        for (int i=0; i<height; i++) {
            System.arraycopy(colors[i],0,a[i],0,seam[i]);//参数说明:原数组,原数组起始点,目标数组,目标数组起始点,长度
            System.arraycopy(colors[i],seam[i]+1,a[i],seam[i],width-seam[i]-1);
        }
        width--;
        colors = a;
    }
    
    public void tailor(int tx,int ty) {
    	int i=0;
    	for(i=1;i<tx;i++) {
    		removeVerticalSeam(findVerticalSeam());
    	}
    	colors=transpose(colors); //矩阵转置,这样可以用同样 的函数处理高度上的缩减
    	for(i=0;i<ty;i++) {
    		removeVerticalSeam(findVerticalSeam());
    	}
    	colors=transpose(colors); //再转置回来
    	return ;
    }
    
    private int[][] transpose(int[][] origin) {
        int temp;
        temp=width;
        width=height;
        height=temp;
    	int[][] result = new int[height][width];
        for(int i = 0; i < height; i++) {
            for(int j = 0; j < width; j++) {
                result[i][j] = origin[j][i];
            }
        }
        return result;
    }
    
    private int red(int rgb) {
        return (rgb >> 16) & 0xFF;
    }
    
    private int green(int rgb) {
        return (rgb >> 8) & 0xFF;
    }
    
    private int blue(int rgb) {
        return (rgb >> 0) & 0xFF;
    }
    
	public static void main(String[] args) {
        Picture picture = new Picture("seamCarving.jpg");
        int dx=0,dy=0;
        Scanner in=new Scanner(System.in);
        dx=in.nextInt();
        dy=in.nextInt();
        in.close();
        seamCarving sc = new seamCarving(picture);
        sc.tailor(dx,dy);
        picture.show(); //显示原图像
        Picture newpicture = sc.picture();
        newpicture.show(); //把sc的colors数组包装为picture对象,再调用picture的show显示修改后的样子
        newpicture.save("swamCarving_result.jpg");
        return ;
    }
	
}

要用到普林斯顿大学的包文件。核心算法就是个dp,没什么大花头,能量函数什么的就不多说了,这么用就行了,原理就说不清了。

知识点补充:

颜色方面的小知识,以白色为例:0xFFFFFFFF 前两个F是透明度的大小,然后是红色的,绿色的,蓝色的亮度。因为是十六进制,所以一个F占四位二进制数,两个占八位,也就是一个byte,代码中要取到红色的值怎么办,很简单,用(rgb >> 16) & 0xFF;,后面十六位舍弃,再和0xFF,(也就是二进制11111111) 位与一下,就截取下来了,绿色蓝色同理。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档