JavaRush /مدونة جافا /Random-AR /عالم البايتات 1. العمل مع الصور.
Joysi
مستوى

عالم البايتات 1. العمل مع الصور.

نشرت في المجموعة
خاص ل وقبل هذا شرحت بأمثلة جافة. لقد طلبوا العمل مع الصور - احصل عليها.
تحديد مهمة التعلم.
إعطاء ملف رسومي (jpeg، png...). من الضروري إجراء بعض المعالجات معه وكتابة النتيجة إلى ملف آخر. للتبسيط، دعونا نفكر في ثلاث مهام: - الحصول على صورة سلبية - الحصول على نسخة بالأبيض والأسود من الصورة (إعادة ضبط اللون) - تغيير تشبع اللون الأخضر في الصورة. لاحظ أنه بطريقة مماثلة يمكننا، من خلال إضافة أساليب جديدة، تنفيذ مهام أخرى: - زيادة الوضوح أو التمويه - تغيير الأبعاد - التدوير في اتجاه عقارب الساعة/عكس اتجاه عقارب الساعة. - وإمكانيات Photoshop الأخرى :) بشكل عام، تنفيذ أي خوارزمية على الصورة، بقدر ما يكون لدينا ما يكفي من الخيال والمعرفة بالمتان (على سبيل المثال، التعرف على عدد القطط المحتملة في الصورة).
نظرية جافة قليلا.
نحن نفكر في الصور النقطية (هناك أيضًا ناقلات وغيرها). أي عندما يقوم الملف، بالإضافة إلى الرأس نفسه الذي يحتوي على معلومات الخدمة، بتخزين مصفوفة مستطيلة من النقاط. تشبه شاشة تلفزيون HD الحديث، والتي تبلغ دقتها 1920 × 1080 بكسل ويتم تمثيل كل بكسل كقيم لثلاثة مكونات لونية: R(ed)، G(reen)، B(lue) = أحمر، أخضر والأزرق. هذه الألوان مستقلة وهذا النموذج مأخوذ من بيولوجيا إدراك الألوان. في العين لدينا المخاريط والقضبان. المخاريط من ثلاثة أنواع (تتفاعل مع النطاق المقابل من نطاقات الطول الموجي الثلاثة)، والقضبان "تعالج" سطوع اللون (سعة موجة الضوء). في نموذج 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