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<Integer, ArrayList> getAllARGB(BufferedImage image){
Map<Integer, ArrayList> result = new HashMap<>();
int width = image.getWidth();
int height = image.getHeight();//height
for(int i = 0; i < height; i++){
ArrayList<int[]> 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<int[]> 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里有没有专门处理二进制数的
放下转黑白前后的对比图