JavaRush /Java Blog /Random-KO /World of Bytes 1. 이미지 작업.
Joysi
레벨 41

World of Bytes 1. 이미지 작업.

Random-KO 그룹에 게시되었습니다
에 특별한 이에 앞서 건전한 예를 들어서 설명했습니다. 그들은 이미지 작업을 요청했습니다.
학습 과제 설정.
그래픽 파일(jpeg, png...)이 주어졌습니다. 이를 사용하여 몇 가지 조작을 수행하고 결과를 다른 파일에 기록해야 합니다. 단순화하기 위해 세 가지 작업을 고려해 보겠습니다. - 네거티브 이미지 가져오기 - 이미지의 흑백 버전 가져오기(색상 재설정) - 이미지의 녹색 채도 변경. 비슷한 방식으로 새로운 메서드를 추가하여 다른 작업을 구현할 수 있습니다. - 선명도 또는 흐림 증가 - 크기 변경 - 시계 방향/시계 반대 방향 회전. - 그리고 Photoshop의 다른 가능성 :) 일반적으로 matan에 대한 충분한 상상력과 지식이 있는 한 이미지에 모든 알고리즘을 구현합니다(예: 사진에서 가능한 고양이 수 인식).
약간 건조한 이론.
우리는 래스터 이미지를 고려하고 있습니다(벡터 이미지 등도 있습니다). 즉, 파일이 서비스 정보가 포함된 헤더 자체 외에도 직사각형 포인트 행렬을 저장하는 경우입니다. 1920x1080 픽셀의 해상도를 갖고 각 픽셀이 R(ed), G(reen), B(lue) = 빨간색, 녹색의 세 가지 색상 구성 요소 값으로 표시되는 최신 HD TV 화면과 유사합니다. 그리고 블루. 이러한 색상은 독립적이며 이 모델은 색상 인식의 생물학에서 가져왔습니다. 눈에는 원뿔과 막대가 있습니다. 세 가지 종류의 원뿔(세 가지 파장 범위 중 해당하는 파장 범위에 반응), 막대는 색상의 밝기(광파의 진폭)를 "처리"합니다. 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