JavaRush /จาวาบล็อก /Random-TH /World of Bytes 1. การทำงานกับรูปภาพ
Joysi
ระดับ

World of Bytes 1. การทำงานกับรูปภาพ

เผยแพร่ในกลุ่ม
พิเศษสำหรับ ก่อนหน้านี้ฉันอธิบายด้วยตัวอย่างคร่าวๆ พวกเขาขอให้ทำงานกับรูปภาพ - เข้าใจสิ
การตั้งค่างานการเรียนรู้
รับไฟล์กราฟิก (jpeg, png...) มีความจำเป็นต้องดำเนินการบางอย่างและเขียนผลลัพธ์ลงในไฟล์อื่น เพื่อให้ง่ายขึ้น ลองพิจารณางานสามอย่าง: - รับภาพเนกาทีฟ - รับภาพเวอร์ชันขาวดำ (รีเซ็ตสี) - เปลี่ยนความอิ่มตัวของสีเขียวในภาพ โปรดทราบว่าในทำนองเดียวกัน เราสามารถใช้งานอื่นๆ ได้โดยการเพิ่มวิธีการใหม่: - เพิ่มความคมชัดหรือเบลอ - เปลี่ยนขนาด - หมุนตามเข็มนาฬิกา/ทวนเข็มนาฬิกา - และความเป็นไปได้อื่น ๆ ของ Photoshop :) โดยทั่วไปแล้ว ใช้อัลกอริธึมใด ๆ กับภาพ เท่าที่เรามีจินตนาการและความรู้เกี่ยวกับ Matan เพียงพอ (เช่น จดจำจำนวนแมวที่เป็นไปได้ในภาพ)
ทฤษฎีแห้งเล็กน้อย
เรากำลังพิจารณาภาพแรสเตอร์ (ยังมีเวกเตอร์และอื่นๆ อีกด้วย) นั่นคือเมื่อไฟล์นอกเหนือจากส่วนหัวที่มีข้อมูลบริการแล้วยังเก็บเมทริกซ์จุดสี่เหลี่ยมอีกด้วย คล้ายกับหน้าจอของ HD TV สมัยใหม่ซึ่งมีความละเอียด 1920x1080 พิกเซล และแต่ละพิกเซลจะแสดงเป็นค่าขององค์ประกอบสี 3 ส่วน ได้แก่ 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 kitty.jpg newkitten.jpg จะสร้างรูปภาพ: เชิงลบ
การเรียกด้วยพารามิเตอร์ -b kitty.jpg newkitten.jpg จะสร้างรูปภาพ: ลูกแมวขาวดำ
การเรียกด้วยพารามิเตอร์ -gr kitty.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