JavaRush /Java 博客 /Random-ZH /字节世界 1. 处理图像。
Joysi
第 41 级

字节世界 1. 处理图像。

已在 Random-ZH 群组中发布
特别适合 在此之前,我用枯燥的例子进行了解释。他们要求使用图像 - 得到它。
设定学习任务。
给定一个图形文件(jpeg、png...)。有必要对其进行一些操作并将结果写入另一个文件。为了简化,让我们考虑三个任务: - 获取负片图像 - 获取图像的黑白版本(重置颜色) - 更改图像中绿色的饱和度。请注意,以类似的方式,我们可以通过添加新方法来实现其他任务: - 增加清晰度或模糊 - 更改尺寸 - 顺时针/逆时针旋转。- 以及 Photoshop 的其他可能性:) 一般来说,只要我们有足够的想象力和 matan 知识,就可以在图像上实现任何算法(例如,识别图片中可能存在的猫的数量)。
有点干理论。
我们正在考虑光栅图像(还有矢量图像和其他图像)。也就是说,当文件除了具有服务信息的标头本身之外还存储点的矩形矩阵时。类似于现代高清电视的屏幕,其分辨率为 1920x1080 像素,每个像素表示为三个颜色分量的值:R(ed)、G(reen)、B(lue) = Red、Green和蓝色。这些颜色是独立的,该模型取自颜色感知的生物学。眼睛里有视锥细胞和视杆细胞。三种视锥细胞(对三个波长范围中相应的一种做出反应),视杆细胞“处理”颜色的亮度(光波的振幅)。在 RGB 模型中,视杆细胞负责分量的值(0 - 不存在,255 - 最亮的光),而视锥细胞 - 分别在 R/G/B 中放置相应的强度。例如:缺乏光线 - 视杆细胞/视锥细胞没有反应,RGB = (0,0,0)。明亮的白光 - 所有视锥细胞反应均匀,视杆细胞疯狂,RGB = (255,255,255)。灰色老鼠跑过——所有视锥细胞反应均匀,视杆细胞反应平均,RGB = (127,127,127)。深橙色 - R 和 G 摇杆有反应,摇杆几乎没有反应,RGB=(30, 30, 0) ...
我们开始练习吧。
我编写了一个使用字节的示例,因此代码没有根据所有规则进行完善,并且远非最佳:我们不检查输入参数,不进行完整的错误检查等。它是直接编写的,没有重构。主要焦点是使用字节位。与 JavaRush 任务类比,让我们编写一个控制台实用程序,当使用适当的参数在命令行上调用时,它会修改图像。 源图片: 猫咪
带参数调用 -n kitten.jpg newkitten.jpg 会创建图片: 消极的
带参数调用 -b kitten.jpg newkitten.jpg 会创建图片: 黑色和白色的小猫
带参数调用 -gr kitten.jpg newkitten.jpg 会创建图片: 暮
其实就是这样
package com.joysi.byteworld; import com.sun.imageio.plugins.jpeg.*; import com.sun.imageio.plugins.png.*; import javax.imageio.*; import javax.imageio.stream.*; import java.awt.image.BufferedImage; import java.io.*; public class image { public static void main(String[] args) throws IOException { CoolImage picture = new CoolImage(args[1]); // загружаем файл изображения if ("-n".equals(args[0])) picture.convertToNegative(); if ("-g".equals(args[0])) picture.addColorGreenChannel(-100); if ("-bw".equals(args[0])) picture.convertToBlackAndWhite(); picture.saveAsJpeg(args[2]); } public static class CoolImage{ private int height; // высота изображения private int width; // ширина изображения private int[] pixels; // собственно массив цветов точек составляющих изображение public int getPixel(int x, int y) { return pixels[y*width+x]; } // получить пиксель в формате RGB public int getRed(int color) { return color >> 16; } // получить красную составляющую цвета public int getGreen(int color) { return (color >> 8) & 0xFF; } // получить зеленую составляющую цвета public int getBlue(int color) { return color & 0xFF;} // получить синюю составляющую цвета // Конструктор - создание изображения из file public CoolImage(String fileName) throws IOException { BufferedImage img = readFromFile(fileName); this.height = img.getHeight(); this.width = img.getWidth(); this.pixels = copyFromBufferedImage(img); } // Чтение изображения из file в BufferedImage private BufferedImage readFromFile(String fileName) throws IOException { ImageReader r = new JPEGImageReader(new JPEGImageReaderSpi()); r.setInput(new FileImageInputStream(new File(fileName))); BufferedImage bi = r.read(0, new ImageReadParam()); ((FileImageInputStream) r.getInput()).close(); return bi; } // Формирование BufferedImage из массива pixels private BufferedImage copyToBufferedImage() { BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) bi.setRGB(j, i, pixels[i*width +j]); return bi; } // Формирование массива пикселей из BufferedImage private int[] copyFromBufferedImage(BufferedImage bi) { int[] pict = new int[height*width]; for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) pict[i*width + j] = bi.getRGB(j, i) & 0xFFFFFF; // 0xFFFFFF: записываем только 3 младших byteа RGB return pict; } // Запись изображения в jpeg-формате public void saveAsJpeg(String fileName) throws IOException { ImageWriter writer = new JPEGImageWriter(new JPEGImageWriterSpi()); saveToImageFile(writer, fileName); } // Запись изображения в png-формате (другие графические форматы по аналогии) public void saveAsPng(String fileName) throws IOException { ImageWriter writer = new PNGImageWriter(new PNGImageWriterSpi()); saveToImageFile(writer, fileName); } // Собственно запись file (общая для всех форматов часть). private void saveToImageFile(ImageWriter iw, String fileName) throws IOException { iw.setOutput(new FileImageOutputStream(new File(fileName))); iw.write(copyToBufferedImage()); ((FileImageOutputStream) iw.getOutput()).close(); } // конвертация изображения в негатив public void convertToNegative() { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) // Применяем логическое отрицание и отбрасываем старший byte pixels[i*width + j] = ~pixels[i*width + j] & 0xFFFFFF; } // конвертация изображения в черно-белый вид public void convertToBlackAndWhite() { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { // находим среднюю арифметическую интенсивность пикселя по всем цветам int intens = (getRed(pixels[i * width + j]) + getGreen(pixels[i * width + j]) + getBlue(pixels[i * width + j])) / 3; // ... и записываем ее в каждый цвет за раз , сдвигая byteы RGB на свои места pixels[i * width + j] = intens + (intens << 8) + (intens << 16); } } // изменяем интесивность зеленого цвета public void addColorGreenChannel(int delta) { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { int newGreen = getGreen(pixels[i * width + j]) + delta; if (newGreen > 255) newGreen=255; // Отсекаем при превышении границ byteа if (newGreen < 0) newGreen=0; // В итоговом пикселе R и B цвета оставляем без изменений: & 0xFF00FF // Полученный новый G (зеленый) засунем в "серединку" RGB: | (newGreen << 8) pixels[i * width + j] = pixels[i * width + j] & 0xFF00FF | (newGreen << 8); } } } }
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION