JavaRush /Blog Java /Random-VI /Thế giới byte 1. Làm việc với hình ảnh.
Joysi
Mức độ

Thế giới byte 1. Làm việc với hình ảnh.

Xuất bản trong nhóm
Đặc biệt dành cho Trước đó, tôi đã giải thích bằng những ví dụ khô khan. Họ yêu cầu làm việc với hình ảnh - hiểu rồi.
Thiết lập nhiệm vụ học tập.
Đưa ra một tệp đồ họa (jpeg, png ...). Cần phải thực hiện một số thao tác với nó và ghi kết quả vào một tệp khác. Để đơn giản hóa, hãy xem xét ba nhiệm vụ: - lấy hình ảnh âm bản - lấy phiên bản đen trắng của hình ảnh (đặt lại màu) - thay đổi độ bão hòa của màu xanh lục trong hình ảnh. Lưu ý rằng theo cách tương tự, chúng ta có thể, bằng cách thêm các phương thức mới, thực hiện các tác vụ khác: - tăng độ sắc nét hoặc độ mờ - thay đổi kích thước - xoay theo chiều kim đồng hồ/ngược chiều kim đồng hồ. - và các khả năng khác của Photoshop :) nói chung, thực hiện bất kỳ thuật toán nào trên hình ảnh, trong chừng mực chúng ta có đủ trí tưởng tượng và kiến ​​​​thức về matan (ví dụ: nhận biết số lượng mèo có thể có trong ảnh).
Một chút lý thuyết khô khan.
Chúng tôi đang xem xét các hình ảnh raster (ngoài ra còn có vector và các hình ảnh khác). Nghĩa là, khi tệp, ngoài tiêu đề có thông tin dịch vụ, còn lưu trữ một ma trận điểm hình chữ nhật. Tương tự như màn hình của TV HD hiện đại, có độ phân giải 1920x1080 pixel và mỗi pixel được biểu diễn dưới dạng giá trị của ba thành phần màu: R(ed), G(reen), B(lue) = Red, Green và màu xanh. Những màu sắc này độc lập và mô hình này được lấy từ nhận thức sinh học về màu sắc. Trong mắt chúng ta có hình nón và hình que. Các tế bào hình nón gồm ba loại (phản ứng với một trong ba dải bước sóng tương ứng), các tế bào hình que “xử lý” độ sáng của màu sắc (biên độ của sóng ánh sáng). Trong mô hình RGB, các thanh chịu trách nhiệm về giá trị của thành phần (0 - vắng mặt, 255 - ánh sáng sáng nhất) và các hình nón - tương ứng, trong đó R / G / B đặt cường độ tương ứng. Ví dụ: Thiếu ánh sáng - tế bào hình que/hình nón không phản ứng và RGB = (0,0,0). Ánh sáng trắng sáng - tất cả các tế bào hình nón phản ứng đồng đều, các tế bào hình que phát điên và RGB = (255,255,255). Chuột xám chạy qua - tất cả các tế bào hình nón phản ứng đều, các tế bào hình que phản ứng trung bình và RGB = (127.127.127). Màu cam đậm - Gậy R và G phản ứng, gậy hầu như không phản hồi, RGB=(30, 30, 0) ...
Hãy bắt đầu luyện tập.
Tôi đã viết một ví dụ về cách làm việc với byte, do đó mã không được trau chuốt theo tất cả các quy tắc và không đạt mức tối ưu: chúng tôi không kiểm tra các tham số đầu vào, không kiểm tra lỗi đầy đủ, v.v. Nó được viết trực tiếp mà không cần tái cấu trúc. Trọng tâm chính là làm việc với byte-bit. Hãy viết, bằng cách tương tự với các tác vụ JavaRush, một tiện ích bảng điều khiển, khi được gọi trên dòng lệnh với các đối số thích hợp, sẽ sửa đổi hình ảnh. Ảnh nguồn: mèo con
gọi với tham số -n kitty.jpg newkitten.jpg sẽ tạo ra một ảnh: tiêu cực
gọi với tham số -b kitty.jpg newkitten.jpg sẽ tạo ra một ảnh: mèo con đen trắng
gọi với tham số -gr kitty.jpg newkitten.jpg sẽ tạo ra một ảnh : Hoàng hôn
Trên thực tế, đó là .
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); } } } }
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION