Java实现RGB转HSI并生成Hue、Saturation、Intensity图像求助
问题:Java实现RGB转HSI并生成H、S、I单通道图像
我正在尝试用Java将RGB图像转换为HSI格式,希望生成三张图像:H-色调图像、S-饱和度图像、I-亮度图像。
我的代码
private void jButton_Convert_HSIActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: BufferedImage image = null; BufferedImage processed_hue, processed_sat, processed_in; try { image = ImageIO.read(new File("C:\\Users\\ATH\\Desktop\\photo\\Rotate\\test_rotate_lena.png")); } catch (IOException ex) { System.out.println(ex.getMessage()); } int width = image.getWidth(); int height = image.getHeight(); processed_hue = new BufferedImage(width, height, image.getType()); processed_sat = new BufferedImage(width, height, image.getType()); processed_in = new BufferedImage(width, height, image.getType()); for (int y = 0; y < width; y++) //thuc hien lap cho y chay tu o den chieu cao anh { for (int x = 0; x < height; x++) //thuc hien lap cho x chay tu 0 den chieu rong { Color c = new Color(image.getRGB(x, y)); float h = 0; float r, g, b, s, i, theta; // RGB TO HSI CONVERSION int red = c.getRed(); int green = c.getGreen(); int blue = c.getBlue(); float total = red + green + blue; r = red / total; g = green / total; b = blue / total; System.out.println("normalize red " + r); System.out.println(" red = " + red + " green = " + green + " blue = " + blue); s = 1 - (3 * Math.min(r, Math.min(g, b))); i = total / (3 * 255); theta = (float) Math.acos((0.5 * ((r - g) + (r - b))) / Math.pow((((r - g) * (r - g)) + ((r - b) * (g - b))), 1 / 2)); System.out.println(" theta " + theta); if (b <= g) { // h = ((1 / Math.cos((0.5 * (2 * r - g - b)) / (Math.sqrt(((r - g) * (r - g) + (r - b) * (g - b))))))); h = theta; } else { h = (float) ((2 * Math.PI) - theta); } System.out.println("Intial hue = " + h + " saturation = " + s + " intensity = " + i); float h1 = (float) (h * (180 / Math.PI)); //to change Radian to Degree - multiply 180/pi float s1 = (s * 100); float i1 = (i * 255); System.out.println(" Hue = " + Math.round(h1) + " Saturation = " + Math.round(s1) + " Intensity = " + Math.round(i1)); // hue float HSV[] = new float[3]; // Color.RGBtoHSB(red, green, blue, HSV); processed_hue.setRGB(x, y, Color.getHSBColor(h1, HSV[1], HSV[2]).getRGB()); // processed_sat.setRGB(x, y, Color.getHSBColor(HSV[0], s1, HSV[2]).getRGB()); // processed_in.setRGB(x, y, Color.getHSBColor(HSV[0], HSV[1], i1).getRGB()); } } // end for loop try { // save images ImageIO.write(processed_hue, "png", new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\hue_image.png")); ImageIO.write(processed_sat, "png", new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\sat_image.png")); ImageIO.write(processed_in, "png", new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\in_image.png")); } catch (IOException ex) { System.out.println(ex.getMessage()); } System.out.println("Image is saved in D drive: "); /* try { File sat_out1 = new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\sat_image.png"); ImageIO.write(sat_image, "png", sat_out1); } catch (IOException ex) { System.out.println(ex.getMessage()); } System.out.println("Image is saved in D drive: "); try { File inten_out1 = new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\inten_image.png"); ImageIO.write(inten_image, "png", inten_out1); } catch (IOException ex) { System.out.println(ex.getMessage()); } System.out.println("Image is saved in D drive: "); */ }
恳请各位提供建议与帮助,我该如何正确获取H、S、I三张图像?
解决方案
我帮你梳理下代码里的问题,以及如何正确生成H、S、I三张单通道图像:
1. 核心问题分析
你的代码里存在几个关键问题,导致无法正确生成目标图像:
- 循环变量颠倒:
y应该遍历图像高度,x遍历宽度,你现在写反了,会导致图像处理错误甚至数组越界。 - 边界情况未处理:当图像像素为纯黑(RGB全0)时,
total=0会触发除以0的错误;当像素为灰度(RGB值相等)时,计算theta的分母为0,会导致Math.acos报错。 - 图像生成逻辑错误:使用
Color.getHSBColor生成的是彩色图像,而你需要的是单通道的H/S/I灰度图像(每个通道的值映射为灰度级)。
2. 修复后的完整代码
private void jButton_Convert_HSIActionPerformed(java.awt.event.ActionEvent evt) { BufferedImage image = null; BufferedImage processed_hue, processed_sat, processed_in; try { image = ImageIO.read(new File("C:\\Users\\ATH\\Desktop\\photo\\Rotate\\test_rotate_lena.png")); } catch (IOException ex) { System.err.println("读取图像失败: " + ex.getMessage()); return; } int width = image.getWidth(); int height = image.getHeight(); processed_hue = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); processed_sat = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); processed_in = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 确保保存目录存在 File outputDir = new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\"); if (!outputDir.exists()) { outputDir.mkdirs(); } // 修正循环:y遍历高度,x遍历宽度 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Color c = new Color(image.getRGB(x, y)); float h = 0; float r = 0, g = 0, b = 0, s = 0, i = 0, theta = 0; int red = c.getRed(); int green = c.getGreen(); int blue = c.getBlue(); float total = red + green + blue; // 处理纯黑像素(避免除以0) if (total == 0) { s = 0; i = 0; h = 0; } else { // 归一化RGB到[0,1]范围 r = red / total; g = green / total; b = blue / total; // 计算饱和度S s = 1 - (3 * Math.min(r, Math.min(g, b))); // 计算亮度I i = total / (3 * 255f); // 计算theta,处理灰度像素(分母为0) float numerator = 0.5f * ((r - g) + (r - b)); float denominator = (float) Math.sqrt(((r - g)*(r - g)) + ((r - b)*(g - b))); if (denominator == 0) { theta = 0; // 灰度像素,色调无意义,设为0 } else { // 确保acos参数在[-1,1]之间,避免报错 float cosTheta = Math.max(-1f, Math.min(1f, numerator / denominator)); theta = (float) Math.acos(cosTheta); } // 计算色调H if (b <= g) { h = theta; } else { h = (float) (2 * Math.PI - theta); } } // 将H/S/I映射到0-255范围,用于生成灰度图像 // H:弧度转0-255 int hValue = (int) ((h / (2 * Math.PI)) * 255); // S:0-1转0-255 int sValue = (int) (s * 255); // I:0-1转0-255 int iValue = (int) (i * 255); // 设置灰度图像(R=G=B=通道值) processed_hue.setRGB(x, y, new Color(hValue, hValue, hValue).getRGB()); processed_sat.setRGB(x, y, new Color(sValue, sValue, sValue).getRGB()); processed_in.setRGB(x, y, new Color(iValue, iValue, iValue).getRGB()); } } // 保存图像 try { ImageIO.write(processed_hue, "png", new File(outputDir, "hue_image.png")); ImageIO.write(processed_sat, "png", new File(outputDir, "sat_image.png")); ImageIO.write(processed_in, "png", new File(outputDir, "in_image.png")); System.out.println("图像已成功保存到目标目录!"); } catch (IOException ex) { System.err.println("保存图像失败: " + ex.getMessage()); } }
3. 关键修复说明
- 循环修正:把
y的循环条件改为y < height,x改为x < width,确保遍历所有像素。 - 边界处理:添加了纯黑像素和灰度像素的特殊处理,避免数学运算错误。
- 图像生成逻辑:将H、S、I的值分别映射到0-255的灰度范围,生成单通道灰度图像(R=G=B),这才是你需要的H/S/I单通道可视化结果。
- 目录创建:提前创建输出目录,避免因目录不存在导致保存失败。
内容的提问来源于stack exchange,提问作者Aye Thu
相关产品推荐
相关产品推荐

