JavaRush /Java Blog /Random-TW /位元組世界 1. 處理圖像。
Joysi
等級 41

位元組世界 1. 處理圖像。

在 Random-TW 群組發布
特別適合 在此之前,我用枯燥的例子進行了解釋。他們要求使用圖像 - 得到它。
設定學習任務。
給定一個圖形檔(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