import javax.imageio.ImageIO;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;import java.util.*;/** * ImageIO的测试类 * */public class Main { public static void main(String[] args) throws IOException { String originPath = "D:/colorTest/001.jpg"; String outputPath = "D:/colorTest/test.jpg"; //1、图片转黑白 changeImageToNoneColor(originPath,outputPath,1); } /** * 图片根据通道转成黑白 * @param originPath 原文件目录 * @param outputPath 输出文件目录 * @param channel 根据哪个通道转黑白 1:Red 2:Green 3:Blue * @throws IOException */ public static void changeImageToNoneColor(String originPath, String outputPath, int channel) throws IOException { File file = new File(originPath); BufferedImage image = ImageIO.read(file); changeAllARGB(image,channel);//将传入的bufferedimage 只保留红色通道的信息 ImageIO.write(image,"jpg",new File(outputPath)); } /** * * @param image BufferedImaged对象 * @return 一个Map Key是图像的像素行数,Value是图像的该行中每一点的ARGB值 */ public static Map getAllARGB(BufferedImage image){ Map result = new HashMap(); int width = image.getWidth(); int height = image.getHeight();//height for(int i = 0; i < height; i++){ ArrayList list = new ArrayList();//用list记录每一行的像素 for(int j = 0; j < width; j++){ int[] transARGB = transARGB(image.getRGB(j, i),-1); list.add(transARGB); } result.put(i,list); } return result; } /** * * @param image * @return */ public static void changeAllARGB(BufferedImage image, int channel){ int width = image.getWidth(); int height = image.getHeight();//height for(int i = 0; i < height; i++){ ArrayList list = new ArrayList();//用list记录每一行的像素 for(int j = 0; j < width; j++){ int[] transARGB = transARGB(image.getRGB(j, i),channel);//获取只显示指定通道图层 //System.out.println("正在处理的像素点坐标 x:" + j + " y:" + i); image.setRGB(j,i,array2Integer(transARGB)); } } } /** * int型rgb转换成数组格式 并保留指定的通道 * @param rgb int型的rgb值 通过BufferedImage的getRGB方法获取的 * @param channel 通道标识 1:Red 2:Green 3:Blue other:保留所有通道 * @return 返回的是int型数组,ARGB四个通道的值 [Alpha,Red,Green,Blue] */ public static int[] transARGB(int rgb, int channel){ String argb = Integer.toBinaryString(rgb); //分割及二进制转换 Integer alpha = Integer.parseInt(argb.substring(0,8),2); Integer red = Integer.parseInt(argb.substring(8,16),2); Integer green = Integer.parseInt(argb.substring(16,24),2); Integer blue = Integer.parseInt(argb.substring(24,32),2); //定义数组 int[] argbArr = {alpha,red,green,blue}; //只保留某一个通道的信息 即把除了Alpha通道外的全部改成所选通道的值 if (channel == 1){ argbArr = new int[]{argbArr[0],argbArr[1],argbArr[1],argbArr[1]}; } if (channel == 2){ argbArr = new int[]{argbArr[0],argbArr[2],argbArr[2],argbArr[2]}; } if (channel == 3){ argbArr = new int[]{argbArr[0],argbArr[3],argbArr[3],argbArr[3]}; } return argbArr; } /** * 获取图像的分辨率 * @return width像素数 * height像素数 */ public static String getSize(BufferedImage image) { int height = image.getHeight(); int width = image.getWidth(); System.out.println("width = " + width); System.out.println("height = " + height); return width + " x " + height; } /** * 只用于此class的方法转换 把记录ARGB的数组转成int信息 * @param arr * @return */ public static int array2Integer(int[] arr){ //System.out.println(Arrays.toString(arr)); //利用Integer.toBinaryString转码时发现一个问题,只会从第一个1开始记录,例如0011100会被记为11100,而我需要的是8位代码 String s1 = get8BitBinaryString(Integer.toBinaryString(arr[0])); String s2 = get8BitBinaryString(Integer.toBinaryString(arr[1])); String s3 = get8BitBinaryString(Integer.toBinaryString(arr[2])); String s4 = get8BitBinaryString(Integer.toBinaryString(arr[3])); String origin = s1 + s2 + s3 + s4; if(origin.startsWith("1")){ //判断首位是否是1,如果是1,则按照补码计算 String[] split = origin.split(""); StringBuilder originCode = new StringBuilder(""); for(int i = 0; i < split.length; i++){ if(split[i].equals("1")){ originCode.append("0"); } if(split[i].equals("0")){ originCode.append("1"); } } //System.out.println(originCode); //循环结果 +1 即为原码 int i = Integer.parseInt(originCode.toString(),2) + 1; System.out.println("-i = " + -i); return -i; } System.out.println(origin); return Integer.parseInt(origin, 2); } /** * 把参数转换为8位二进制代码 * @param s * @return */ public static String get8BitBinaryString (String s){ if(s.length() == 8){ return s; }else{ int length = s.length(); String zero = ""; for (int i = 0; i < 8 - length; i++){/*通过循环判断前面要加几个零*/ zero += "0"; } return zero + s; } }}
想实现一个通过JAVA把视频转成字符画视频的功能,作为一个小工具放在个人论坛上。
实现视频转成字符画视频首先要能把图片转成字符画“,思路就是先把图片解析成黑白图片 -- > 每个像素点用字符替代 -->生成一个字符画 首先这个图片解析成黑白就难到我了,查了下图像处理的相关API,发现了这个ImageIO类
然后搞了一个晚上搞出来这个小demo,搞的时候发现其实不用解析成黑白图片,read的时候直接把RGB像素变成字符输出就好了,但是黑白图片这个功能毕竟已经做了一半,就顺手记录下;
踩坑:
这个主要是调用API,坑不多,主要是两点
Integer.toBinaryString()如果参数是负数 那么return的就是补码 不能把这个数再通过Integer.parseInt()直接转成int,会报错Integer.toBinaryString转码时,只会从第一个1开始记录,例如0011100会被记为11100,而我需要的是用来记录ARGB每个通道的值8位二进制数字(0~255),所以要处理下,目前这个处理方式性能很差,改天看看api里有没有专门处理二进制数的
放下转黑白前后的对比图