মিনিয়েচার ফেকিং


26

যেভাবে কোনও অপেশাদার ফটোগ্রাফার আপনাকে বলতে পারেন, চরম পোস্ট-প্রসেসিং সবসময় ভাল। এ জাতীয় একটি কৌশলকে বলা হয় " মিনিয়েচার ফেকিং "।

অবজেক্টটি হ'ল কোনও চিত্রকে নিজের একটি ক্ষুদ্রাকৃতির, খেলনা সংস্করণের ফটোগ্রাফের মতো দেখায়। এটি মধ্যম / উচ্চ কোণ থেকে স্থলটিতে তোলা ফটোগ্রাফগুলির জন্য সবচেয়ে ভাল কাজ করে, বিষয়টির উচ্চতায় কম বৈচিত্র্য সহ, তবে অন্যান্য চিত্রগুলিতে বিভিন্ন কার্যকারিতা সহ প্রয়োগ করা যেতে পারে।

চ্যালেঞ্জ: একটি ছবি তুলুন এবং এটিতে একটি ক্ষুদ্র-ফ্যাকিং অ্যালগরিদম প্রয়োগ করুন। এটি করার অনেকগুলি উপায় রয়েছে তবে এই চ্যালেঞ্জের উদ্দেশ্যে এটি এটিকে ফুটিয়ে তোলে:

  • নির্বাচনী অস্পষ্টতা

    চিত্রের কিছু অংশ অস্পষ্টভাবে জমির অগভীর গভীরতা অনুকরণ করতে হবে। এটি সাধারণত কিছু গ্রেডিয়েন্ট বরাবর সম্পন্ন হয়, লিনিয়ার বা আকারযুক্ত যাই হোক না কেন। আপনার অস্পষ্ট / গ্রেডিয়েন্ট অ্যালগরিদম যা পছন্দ করুন তা চয়ন করুন তবে চিত্রের 15-85% এর মধ্যে অবশ্যই "লক্ষণীয়" ঝাপসা থাকতে হবে।

  • স্যাচুরেশন বুস্ট

    জিনিসগুলি প্রদর্শিত হওয়ার জন্য রঙটি পাম্প করুন যা তারা হাতে আঁকা হয়েছিল। ইনপুটটির সাথে তুলনা করলে আউটপুটটির অবশ্যই গড় স্যাচুরেশন স্তর> + 5% থাকতে হবে। ( এইচএসভি স্যাচুরেশন ব্যবহার করে )

  • কনট্রাস্ট বুস্ট

    কঠোর আলোকসজ্জার শর্তগুলির অনুকরণের বিপরীতে বৃদ্ধি করুন (যেমন আপনি সূর্যের চেয়ে কোনও অভ্যন্তরীণ / স্টুডিওর আলো দিয়ে দেখেন)। ইনপুটটির সাথে তুলনা করলে আউটপুটটিতে> + 5% এর বিপরীতে থাকতে হবে। ( আরএমএস অ্যালগরিদম ব্যবহার করে )

এই তিনটি পরিবর্তন অবশ্যই প্রয়োগ করা উচিত এবং অন্য কোনও বর্ধন / পরিবর্তন অনুমোদিত নয়। কোনও ক্রপিং, তীক্ষ্ণ করা, সাদা ব্যালেন্স সামঞ্জস্য নেই, কিছুই নেই।

  • ইনপুট একটি চিত্র, এবং একটি ফাইল বা মেমরি থেকে পড়া যায়। আপনি ছবিটি পড়তে এবং লিখতে বাহ্যিক গ্রন্থাগারগুলি ব্যবহার করতে পারেন তবে আপনি চিত্রটি প্রক্রিয়া করার জন্য সেগুলি ব্যবহার করতে পারবেন না । সরবরাহিত ক্রিয়াকলাপগুলিও এই উদ্দেশ্যে অনুমোদিত নয় (আপনি কেবল উদাহরণ হিসাবে কল করতে পারবেন না )Image.blur()

  • অন্য কোনও ইনপুট নেই। প্রসেসিং শক্তি, স্তর ইত্যাদি অবশ্যই কোনও মানুষ দ্বারা নয়, প্রোগ্রাম দ্বারা নির্ধারিত হতে হবে।

  • আউটপুট একটি মানকৃত চিত্র ফর্ম্যাটে (পিএনজি, বিএমপি, ইত্যাদি) ফাইল হিসাবে প্রদর্শিত বা সংরক্ষণ করা যায় saved

  • সাধারণীকরণের চেষ্টা করুন। এটি কেবল একটি চিত্রের জন্য কাজ করা উচিত নয় তবে এটি বোধগম্য যে এটি সমস্ত চিত্রে কাজ করবে না । কিছু দৃশ্য সহজেই এই প্রযুক্তিতে ভাল প্রতিক্রিয়া জানায় না, যতই ভাল অ্যালগরিদম না কেন। উত্তর দেওয়ার সময় এবং জবাব দেওয়ার সময় উভয়ই এখানে সাধারণ জ্ঞান প্রয়োগ করুন।

  • আচরণটি অবৈধ ইনপুটগুলির জন্য অপরিজ্ঞাত, এবং সেই চিত্রগুলি যা চশমাটি পূরণ করা অসম্ভব। উদাহরণস্বরূপ, গ্রেস্কেল চিত্রটি স্যাচুরেট করা যায় না (কোনও বেস হিউ নেই), একটি খাঁটি সাদা ছবিযুক্ত কনট্রাস্ট বৃদ্ধি করতে পারে না ইত্যাদি etc.

  • আপনার উত্তরে কমপক্ষে দুটি আউটপুট চিত্র অন্তর্ভুক্ত করুন:

    এই ড্রপবক্স ফোল্ডারের কোনও একটি থেকে অবশ্যই উত্পন্ন করা উচিত । ছয়টি বাছাই করতে হবে তবে আমি সেগুলি বিভিন্ন ডিগ্রীতে কার্যকর করার চেষ্টা করেছি। আপনি example-outputsসাবফোল্ডারে প্রতিটি জন্য নমুনা আউটপুট দেখতে পারেন । দয়া করে মনে রাখবেন যে এগুলি পুরো 10 এমপি জেপিজি চিত্রগুলি সরাসরি ক্যামেরার বাইরে, সুতরাং আপনার কাজ করার জন্য প্রচুর পিক্সেল রয়েছে।

    অন্যটি আপনার পছন্দের কোনও চিত্র হতে পারে। স্পষ্টতই, অবাধে ব্যবহারযোগ্য এমন চিত্র চয়ন করার চেষ্টা করুন। এছাড়াও, তুলনা করার জন্য মূল চিত্র বা এর কোনও লিঙ্ক অন্তর্ভুক্ত করুন।


উদাহরণস্বরূপ, এই চিত্রটি থেকে:

মূল

আপনি যেমন কিছু আউটপুট হতে পারে:

প্রক্রিয়াজাত

রেফারেন্সের জন্য, উপরের উদাহরণটি জিআইএমপিতে একটি কৌণিক বাক্সের আকারের গ্রেডিয়েন্ট গাউসিয়ান ব্লার, স্যাচুরেশন +80, বিপরীতে +20 দিয়ে প্রক্রিয়া করা হয়েছিল। (আমি জানি না জিআইএমপি সেগুলির জন্য কী ইউনিটগুলি ব্যবহার করে)

আরও অনুপ্রেরণার জন্য, বা আপনি কী অর্জন করতে চাইছেন সে সম্পর্কে আরও ভাল ধারণা পেতে, এই সাইটটি বা এটির একটি দেখুন । আপনি উদাহরণ miniature fakingএবং tilt shift photographyজন্য অনুসন্ধান করতে পারেন ।


এটি একটি জনপ্রিয়তা প্রতিযোগিতা। ভোটারগণ, উদ্দেশ্যটির প্রতি সত্য থাকায় আপনি যে ভুক্তিগুলি সবচেয়ে ভাল বলে মনে করছেন তাদের পক্ষে ভোট দিন।


ব্যাখ্যা:

কোন ফাংশনগুলি অনুমোদিত নয় তা স্পষ্ট করে গণিত ফাংশন নিষিদ্ধ করার আমার উদ্দেশ্য ছিল না । ইমেজ ম্যানিপুলেশন ফাংশন নিষিদ্ধ করার আমার উদ্দেশ্য ছিল । হ্যাঁ, সেখানে কিছুটা ওভারল্যাপ রয়েছে, তবে এফএফটি, কনভলিউশনস, ম্যাট্রিক্স গণিত ইত্যাদি জিনিসগুলি অন্যান্য অনেক ক্ষেত্রে কার্যকর many আপনার এমন কোনও ফাংশন ব্যবহার করা উচিত নয় যা কেবল একটি চিত্র নেয় এবং ঝাপসা হয়। যদি আপনি একটি অস্পষ্টতা তৈরি করার উপযুক্ত ম্যাথিক উপায় খুঁজে পান তবে সেই সুষ্ঠু গেমটি।


ইউ-সুং চ্যাং দ্বারা ডিজিটাল টিল্ট-শিফ্ট চিত্র প্রসেসিংয়ের উপর এই লক্ষণীয় বিক্ষোভের প্রদর্শনগুলি: ওল্ফ্রাম.com/ ডিজিটালটিল্ট শিফটফটোগ্রাফি, বৈসাদৃশ্য, উজ্জ্বলতা এবং স্থানীয় ফোকাসকে কীভাবে সামঞ্জস্য করা যায় সে সম্পর্কে ধারণা প্রচুর উপস্থাপন করে (ছবির ডিম্বাকৃতি বা আয়তক্ষেত্রাকার অঞ্চলে) ) ব্যবহার করে বিল্ট-ইন ম্যাথামেটিকাল কার্যাবলী ( GeometricTransformation, DistanceTransform, ImageAdd, ColorNegate, ImageMultiply, Rasterize, এবং ImageAdjust।) এমনকী যেমন উচ্চ স্তর ইমেজ প্রক্রিয়াকরণ ফাংশন সাহায্যে, কোড আপ 22 ট লাগে। ইউজার ইন্টারফেসের কোডটি তবে খুব ছোট।
ডেভিডসি

5
আমার বলা উচিত ছিল " কেবল 22 কে" নেয় । উপরে উল্লিখিত ফাংশনগুলিতে নেপথ্য দৃশ্যের পিছনে পর্দার কোডগুলি রয়েছে যা এই চ্যালেঞ্জটির সফল প্রতিক্রিয়াটি ডেডিকেটেড চিত্র-প্রসেসিং লাইব্রেরি ব্যবহার না করে বেশিরভাগ ভাষায় অর্জন করা খুব, খুব কঠিন প্রমাণিত উচিত।
ডেভিডসি

আপডেট: এটি 2.5 কে অক্ষরে করা হয়েছিল যাতে এটি আরও কার্যকর ছিল।
ডেভিডসি

1
@ ডেভিডকারারহর এই কারণেই আমি স্পষ্টভাবে এই অনুমিতিটি সীমাবদ্ধ রেখেছি। কেবল অনুমানটি কভার করার জন্য কিছু লেখা শক্ত নয়, কারণ নীচে আমার রেফারেন্স প্রয়োগটি নিরবচ্ছিন্ন জাভার ৪.৩ কে অক্ষরে দেখায় । আমি পুরোপুরি পেশাদার-স্টুডিও-স্তরের ফলাফল আশা করি না। অবশ্যই, স্প্যামের চেয়ে বেশি যে কোনও কিছু (ভাল ফলাফলের দিকে পরিচালিত করে) আন্তরিকভাবে উত্সাহিত করা উচিত, আইএমও। আমি সম্মতি জানাই যে এটি অর্জন করা সহজ চ্যালেঞ্জ নয় , তবে এটি হওয়ার কথা ছিল না। সর্বনিম্ন প্রচেষ্টা বেসিক, তবে "ভাল" এন্ট্রি অগত্যা আরও জড়িত হবে।
জিওবিটস

আরও দৃinc়প্রত্যয়ী "মিনিয়েচারস" তৈরি করতে এগুলির সাথে একত্রিত হতে পারে এমন আরও একটি অ্যালগরিদম হ'ল বড় বৈশিষ্ট্যগুলি তীক্ষ্ণ রাখার পাশাপাশি চিত্র থেকে ছোট বৈশিষ্ট্যগুলি ছাঁটাই করতে তরঙ্গলেখের পচন ব্যবহার করা।
এজেম্যান্সফিল্ড

উত্তর:


15

জাভা: রেফারেন্স বাস্তবায়ন

জাভাতে এখানে একটি প্রাথমিক রেফারেন্স বাস্তবায়ন। এটি উচ্চ-কোণের শটে সেরা কাজ করে এবং এটি মারাত্মকভাবে অক্ষম।

অস্পষ্টতা একটি খুব মৌলিক বাক্সের অস্পষ্টতা, তাই এটি একই পিক্সেলের উপরে প্রয়োজনীয়ের চেয়ে অনেক বেশি লুপ হয়। বৈসাদৃশ্য এবং স্যাচুরেশনকে একটি একক লুপেও সংযুক্ত করা যেতে পারে, তবে ব্যয় করা বেশিরভাগ সময় অস্পষ্ট হয়ে যায়, সুতরাং এটি থেকে খুব বেশি লাভ দেখা যায় না। বলা হচ্ছে, এটি 2 এমপি বা তারও অধীনে চিত্রগুলিতে মোটামুটি দ্রুত কাজ করে। 10 এমপি চিত্রটি সম্পূর্ণ হতে কিছুটা সময় নিয়েছে।

মূলত ফ্ল্যাট বাক্সের অস্পষ্টতা বাদে কিছুই ব্যবহার করে অস্পষ্ট মানের সহজেই উন্নতি করা যায় । বিপরীতে / স্যাচুরেশন আলগোরিদিমগুলি তাদের কাজ করে, সুতরাং সেখানে কোনও আসল অভিযোগ নেই।

প্রোগ্রামটিতে সত্যিকারের কোনও বুদ্ধি নেই। এটি অস্পষ্টতা, স্যাচুরেশন এবং বৈপরীত্যের জন্য ধ্রুবক কারণগুলি ব্যবহার করে। আমি খুশি মাঝারি সেটিংস এটির সাথে এটির সাথে খেলেছি played ফলস্বরূপ, সেখানে হয় কিছু দৃশ্য যে এটা খুব ভাল করতে নেই। উদাহরণস্বরূপ, এটি বৈপরীত্য / স্যাচুরেশনকে এত বেশি পাম্প করে যে বৃহত্তর অনুরূপ বর্ণযুক্ত অঞ্চলগুলি (মনে করি আকাশ) রঙিন ব্যান্ডগুলিতে বিভক্ত হয়।

এটি ব্যবহার করা সহজ; কেবলমাত্র যুক্তি হিসাবে ফাইলের নামটি দিন। ইনপুট ফাইলটি নির্বিশেষে এটি পিএনজিতে আউটপুট দেয়।

উদাহরণ:

ড্রপবক্স নির্বাচন থেকে:

এই প্রথম চিত্রগুলি সহজেই পোস্ট করার জন্য ছোট করে দেওয়া হয়। পূর্ণ আকার দেখতে ছবিতে ক্লিক করুন.

পরে:

এখানে চিত্র বর্ণনা লিখুন

আগে:

এখানে চিত্র বর্ণনা লিখুন

বিবিধ নির্বাচন:

পরে:

এখানে চিত্র বর্ণনা লিখুন

আগে:

এখানে চিত্র বর্ণনা লিখুন

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class MiniFake {

    int maxBlur;
    int maxDist;
    int width;
    int height;

    public static void main(String[] args) {
        if(args.length < 1) return;
        new MiniFake().run(args[0]);
    }

    void run(String filename){
        try{
            BufferedImage in = readImage(filename);
            BufferedImage out = blur(in);
            out = saturate(out, 0.8);
            out = contrast(out, 0.6);

            String[] tokens = filename.split("\\.");
            String outname = tokens[0];
            for(int i=1;i<tokens.length-1;i++)
                outname += "." + tokens[i];
            ImageIO.write(out, "png", new File(outname + "_post.png"));
            System.out.println("done");
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    BufferedImage contrast(BufferedImage in, double level){
        BufferedImage out = copyImage(in);
        long lumens=0;
        for(int x=0;x<width;x++)
            for(int y=0;y<height;y++){
                int color = out.getRGB(x,y);
                lumens += lumen(getR(color), getG(color), getB(color));
            }
        lumens /= (width * height);

        for(int x=0;x<width;x++)
            for(int y=0;y<height;y++){
                int color = out.getRGB(x,y);
                int r = getR(color);
                int g = getG(color);
                int b = getB(color);
                double ratio = ((double)lumen(r, g, b) / (double)lumens) - 1d;
                ratio *= (1+level) * 0.1;
                r += (int)(getR(color) * ratio+1);
                g += (int)(getG(color) * ratio+1);
                b += (int)(getB(color) * ratio+1);
                out.setRGB(x,y,getColor(clamp(r),clamp(g),clamp(b)));
            }   
        return out;
    }

    BufferedImage saturate(BufferedImage in, double level){
        BufferedImage out = copyImage(in);
        for(int x=0;x<width;x++)
            for(int y=0;y<height;y++){
                int color = out.getRGB(x,y);
                int r = getR(color);
                int g = getG(color);
                int b = getB(color);
                int brightness = Math.max(r, Math.max(g, b));
                int grey = (int)(Math.min(r, Math.min(g,b)) * level);
                if(brightness == grey)
                    continue;
                r -= grey;
                g -= grey;
                b -= grey;
                double ratio = brightness / (double)(brightness - grey);
                r = (int)(r * ratio);
                g = (int)(g * ratio);
                b = (int)(b * ratio);
                out.setRGB(x, y, getColor(clamp(r),clamp(g),clamp(b)));
            }
        return out;
    }


    BufferedImage blur(BufferedImage in){
        BufferedImage out = copyImage(in);
        int[] rgb = in.getRGB(0, 0, width, height, null, 0, width);
        for(int i=0;i<rgb.length;i++){
            double dist = Math.abs(getY(i)-(height/2));
            dist = dist * dist / maxDist;
            int r=0,g=0,b=0,p=0;
            for(int x=-maxBlur;x<=maxBlur;x++)
                for(int y=-maxBlur;y<=maxBlur;y++){
                    int xx = getX(i) + x;
                    int yy = getY(i) + y;
                    if(xx<0||xx>=width||yy<0||yy>=height)
                        continue;
                    int color = rgb[getPos(xx,yy)];
                    r += getR(color);
                    g += getG(color);
                    b += getB(color);
                    p++;
                }

            if(p>0){
                r /= p;
                g /= p;
                b /= p;
                int color = rgb[i];
                r = (int)((r*dist) + (getR(color) * (1 - dist)));
                g = (int)((g*dist) + (getG(color) * (1 - dist)));
                b = (int)((b*dist) + (getB(color) * (1 - dist)));
            } else {
                r = in.getRGB(getX(i), getY(i));
            }
            out.setRGB(getX(i), getY(i), getColor(r,g,b));
        }
        return out;
    }

    BufferedImage readImage(String filename) throws IOException{
         BufferedImage image = ImageIO.read(new File(filename));
         width = image.getWidth();
         height = image.getHeight();
         maxBlur = Math.max(width, height) / 100;
         maxDist =  (height/2)*(height/2);
         return image;
    }

    public BufferedImage copyImage(BufferedImage in){
        BufferedImage out = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics g = out.getGraphics();
        g.drawImage(in, 0, 0, null);
        g.dispose();
        return out;
    }

    static int clamp(int c){return c<0?0:c>255?255:c;}
    static int getColor(int a, int r, int g, int b){return (a << 24) | (r << 16) | (g << 8) | (b);}
    static int getColor(int r, int g, int b){return getColor(0xFF, r, g, b);}
    static int getR(int color){return color >> 16 & 0xFF;}
    static int getG(int color){return color >> 8 & 0xFF;}
    static int getB(int color){return color & 0xFF;}
    static int lumen(int r, int g, int b){return (r*299)+(g*587)+(b*114);}
    int getX(int pos){return pos % width;}
    int getY(int pos){return pos / width;}
    int getPos(int x, int y){return y*width+x;} 
}

12

সি শার্প

কোনও পুনরাবৃত্ত বাক্স ঝাপসা করার পরিবর্তে, আমি পুরো পথে যেতে এবং একটি গাউসিয়ান ব্লার লেখার সিদ্ধান্ত নিয়েছি। GetPixelকল সত্যিই যখন বড় কার্নেলের ব্যবহার করে এটি মন্দীভূত, কিন্তু এটা ব্যবহার করা পদ্ধতি রূপান্তর করতে উপযুক্ত সত্যিই না LockBitsযদি না আমরা কিছু বৃহত্তর চিত্র প্রক্রিয়াকরণের হয়।

কিছু উদাহরণ নীচে রয়েছে, যা আমি নির্ধারিত ডিফল্ট টিউনিং প্যারামিটারগুলি ব্যবহার করি (আমি টিউনিং প্যারামিটারগুলির সাথে বেশি খেলিনি, কারণ তারা পরীক্ষার চিত্রটির জন্য ভাল কাজ করেছে বলে মনে হয়)।

প্রদত্ত পরীক্ষার ক্ষেত্রে ...

1-মূল 1-সংশোধিত

আরেকটি ...

2-মূল 2-সংশোধিত

আরেকটি ...

3-মূল 3-সংশোধিত

সম্পৃক্তি এবং বিপরীতে বৃদ্ধি কোড থেকে মোটামুটি সোজা হওয়া উচিত। আমি এইচএসএল স্পেসে এটি করি এবং এটি আরজিবিতে রূপান্তর করি।

2D গসিয়ান কার্নেল আকারের উপর ভিত্তি করে উৎপন্ন হয় nনিদিষ্ট সঙ্গে:

EXP(-((x-x0)^2/2+(y-y0)^2/2)/2)

... এবং সমস্ত কার্নেল মান নির্ধারিত হওয়ার পরে স্বাভাবিক করা হয়েছে। নোট করুন A=sigma_x=sigma_y=1

কার্নেলটি কোথায় প্রয়োগ করবেন তা নির্ধারণ করার জন্য, আমি একটি ঝাপসা ওজন ব্যবহার করি, এটি দ্বারা গণনা করা হয়:

SQRT([COS(PI*x_norm)^2 + COS(PI*y_norm)^2]/2)

... যা একটি শালীন প্রতিক্রিয়া দেয়, মূলত অস্পষ্টতা থেকে সুরক্ষিত মানগুলির একটি উপবৃত্ত তৈরি করে যা ধীরে ধীরে আরও বিবর্ণ হয়। অন্যান্য সমীকরণগুলির সাথে মিলিত একটি ব্যান্ড-পাস ফিল্টার (সম্ভবত কিছু বৈকল্পিক y=-x^2) নির্দিষ্ট চিত্রগুলির জন্য এখানে আরও ভালভাবে কাজ করতে পারে। আমি কোজিনের সাথে চলেছি কারণ এটি আমার পরীক্ষিত বেস কেসটির জন্য একটি ভাল প্রতিক্রিয়া দিয়েছে।

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace FakeMini
{
    static class Program
    {
        static void Main()
        {
            // Some tuning variables
            double saturationValue = 1.7;
            double contrastValue = 1.2;
            int gaussianSize = 13; // Must be odd and >1 (3, 5, 7...)

            // NxN Gaussian kernel
            int padding = gaussianSize / 2;
            double[,] kernel = GenerateGaussianKernel(gaussianSize);

            Bitmap src = null;
            using (var img = new Bitmap(File.OpenRead("in.jpg")))
            {
                src = new Bitmap(img);
            }

            // Bordering could be avoided by reflecting or wrapping instead
            // Also takes advantage of the fact that a new bitmap returns zeros from GetPixel
            Bitmap border = new Bitmap(src.Width + padding*2, src.Height + padding*2);

            // Get average intensity of entire image
            double intensity = 0;
            for (int x = 0; x < src.Width; x++)
            {
                for (int y = 0; y < src.Height; y++)
                {
                    intensity += src.GetPixel(x, y).GetBrightness();
                }
            }
            double averageIntensity = intensity / (src.Width * src.Height);

            // Modify saturation and contrast
            double brightness;
            double saturation;
            for (int x = 0; x < src.Width; x++)
            {
                for (int y = 0; y < src.Height; y++)
                {
                    Color oldPx = src.GetPixel(x, y);
                    brightness = oldPx.GetBrightness();
                    saturation = oldPx.GetSaturation() * saturationValue;

                    Color newPx = FromHSL(
                                oldPx.GetHue(),
                                Clamp(saturation, 0.0, 1.0),
                                Clamp(averageIntensity - (averageIntensity - brightness) * contrastValue, 0.0, 1.0));
                    src.SetPixel(x, y, newPx);
                    border.SetPixel(x+padding, y+padding, newPx);
                }
            }

            // Apply gaussian blur, weighted by corresponding sine value based on height
            double blurWeight;
            Color oldColor;
            Color newColor;
            for (int x = padding; x < src.Width+padding; x++)
            {
                for (int y = padding; y < src.Height+padding; y++)
                {
                    oldColor = border.GetPixel(x, y);
                    newColor = Convolve2D(
                        kernel,
                        GetNeighbours(border, gaussianSize, x, y)
                       );

                    // sqrt([cos(pi*x_norm)^2 + cos(pi*y_norm)^2]/2) gives a decent response
                    blurWeight = Clamp(Math.Sqrt(
                        Math.Pow(Math.Cos(Math.PI * (y - padding) / src.Height), 2) +
                        Math.Pow(Math.Cos(Math.PI * (x - padding) / src.Width), 2)/2.0), 0.0, 1.0);
                    src.SetPixel(
                        x - padding,
                        y - padding,
                        Color.FromArgb(
                            Convert.ToInt32(Math.Round(oldColor.R * (1 - blurWeight) + newColor.R * blurWeight)),
                            Convert.ToInt32(Math.Round(oldColor.G * (1 - blurWeight) + newColor.G * blurWeight)),
                            Convert.ToInt32(Math.Round(oldColor.B * (1 - blurWeight) + newColor.B * blurWeight))
                            )
                        );
                }
            }
            border.Dispose();

            // Configure some save parameters
            EncoderParameters ep = new EncoderParameters(3);
            ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            ep.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, (int)EncoderValue.ScanMethodInterlaced);
            ep.Param[2] = new EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, (int)EncoderValue.RenderProgressive);
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            ImageCodecInfo ici = null;
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.MimeType == "image/jpeg")
                    ici = codec;
            }
            src.Save("out.jpg", ici, ep);
            src.Dispose();
        }

        // Create RGB from HSL
        // (C# BCL allows me to go one way but not the other...)
        private static Color FromHSL(double h, double s, double l)
        {
            int h0 = Convert.ToInt32(Math.Floor(h / 60.0));
            double c = (1.0 - Math.Abs(2.0 * l - 1.0)) * s;
            double x = (1.0 - Math.Abs((h / 60.0) % 2.0 - 1.0)) * c;
            double m = l - c / 2.0;
            int m0 = Convert.ToInt32(255 * m);
            int c0 = Convert.ToInt32(255*(c + m));
            int x0 = Convert.ToInt32(255*(x + m));
            switch (h0)
            {
                case 0:
                    return Color.FromArgb(255, c0, x0, m0);
                case 1:
                    return Color.FromArgb(255, x0, c0, m0);
                case 2:
                    return Color.FromArgb(255, m0, c0, x0);
                case 3:
                    return Color.FromArgb(255, m0, x0, c0);
                case 4:
                    return Color.FromArgb(255, x0, m0, c0);
                case 5:
                    return Color.FromArgb(255, c0, m0, x0);
            }
            return Color.FromArgb(255, m0, m0, m0);
        }

        // Just so I don't have to write "bool ? val : val" everywhere
        private static double Clamp(double val, double min, double max)
        {
            if (val >= max)
                return max;
            else if (val <= min)
                return min;
            else
                return val;
        }

        // Simple convolution as C# BCL doesn't appear to have any
        private static Color Convolve2D(double[,] k, Color[,] n)
        {
            double r = 0;
            double g = 0;
            double b = 0;
            for (int i=0; i<k.GetLength(0); i++)
            {
                for (int j=0; j<k.GetLength(1); j++)
                {
                    r += n[i,j].R * k[i,j];
                    g += n[i,j].G * k[i,j];
                    b += n[i,j].B * k[i,j];
                }
            }
            return Color.FromArgb(
                Convert.ToInt32(Math.Round(r)),
                Convert.ToInt32(Math.Round(g)),
                Convert.ToInt32(Math.Round(b)));
        }

        // Generates a simple 2D square (normalized) Gaussian kernel based on a size
        // No tuning parameters - just using sigma = 1 for each
        private static double [,] GenerateGaussianKernel(int n)
        {
            double[,] kernel = new double[n, n];
            double currentValue;
            double normTotal = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    currentValue = Math.Exp(-(Math.Pow(i - n / 2, 2) + Math.Pow(j - n / 2, 2)) / 2.0);
                    kernel[i, j] = currentValue;
                    normTotal += currentValue;
                }
            }
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    kernel[i, j] /= normTotal;
                }
            }
            return kernel;
        }

        // Gets the neighbours around the current pixel
        private static Color[,] GetNeighbours(Bitmap bmp, int n, int x, int y)
        {
            Color[,] neighbours = new Color[n, n];
            for (int i = -n/2; i < n-n/2; i++)
            {
                for (int j = -n/2; j < n-n/2; j++)
                {
                    neighbours[i+n/2, j+n/2] = bmp.GetPixel(x + i, y + j);
                }
            }
            return neighbours;
        }
    }
}

9

জাভা

গাউসিয়ান ব্লারকে অনুকরণ করে একাধিক পাস চালানোর জন্য দ্রুত গতিতে দ্রুত চলমান গড় দ্বিমুখী বাক্সের ঝাপসা ব্যবহার করে Uses অস্পষ্টতা দ্বি-লিনিয়ার পরিবর্তে একটি উপবৃত্তাকার গ্রেডিয়েন্ট।

দৃশ্যত, এটি বড় চিত্রগুলিতে সেরা কাজ করে। একটি গাer়, গ্রুঙ্গিয়ার থিম রয়েছে। যথাযথ আকারের চিত্রগুলিতে অস্পষ্টতাটি কীভাবে পরিণত হয়েছিল তা নিয়ে আমি সন্তুষ্ট, এটি কোথায় "শুরু হয়" এটি বেশ ধীরে ধীরে এবং এটি নির্ধারণ করা শক্ত।

পূর্ণসংখ্যা বা ডাবল (এইচএসভির জন্য) এর অ্যারেতে করা সমস্ত গণনা।

আর্গুমেন্ট হিসাবে ফাইলের পথের প্রত্যাশা, প্রত্যয় "মিনিটায়ারাইজড.পিএনজি" সহ একই স্থানে ফাইল আউটপুট দেয় তাৎক্ষণিক দেখার জন্য জেফ্রেমে ইনপুট এবং আউটপুট প্রদর্শন করে।

(বড় সংস্করণ দেখতে ক্লিক করুন, সেগুলি আরও ভাল)

আগে:

http://i.imgur.com/cOPl6EOl.jpg

পরে:

এখানে চিত্র বর্ণনা লিখুন

আমাকে কিছু স্মার্ট টোন ম্যাপিং বা লুমা সংরক্ষণ যুক্ত করতে হতে পারে, কারণ এটি বেশ অন্ধকার পেতে পারে:

আগে:

এখানে চিত্র বর্ণনা লিখুন

পরে:

এখানে চিত্র বর্ণনা লিখুন

এখনও আকর্ষণীয় যদিও এটি একটি সম্পূর্ণ নতুন পরিবেশে রাখে।

কোড:

import java.awt.*;
import java.awt.image.*;
import java.io.*;

import javax.imageio.*;
import javax.swing.*;

public class SceneMinifier {

    static final double CONTRAST_INCREASE = 8;
    static final double SATURATION_INCREASE = 7;

    public static void main(String[] args) throws IOException {

        if (args.length < 1) {
            System.out.println("Please specify an input image file.");
            return;
        }

        BufferedImage temp = ImageIO.read(new File(args[0]));

        BufferedImage input = new BufferedImage(temp.getWidth(), temp.getHeight(), BufferedImage.TYPE_INT_ARGB);
        input.getGraphics().drawImage(temp, 0, 0, null); // just want to guarantee TYPE_ARGB

        int[] pixels = ((DataBufferInt) input.getData().getDataBuffer()).getData();

        // saturation

        double[][] hsv = toHSV(pixels);
        for (int i = 0; i < hsv[1].length; i++)
            hsv[1][i] = Math.min(1, hsv[1][i] * (1 + SATURATION_INCREASE / 10));

        // contrast

        int[][] rgb = toRGB(hsv[0], hsv[1], hsv[2]);

        double c = (100 + CONTRAST_INCREASE) / 100;
        c *= c;

        for (int i = 0; i < pixels.length; i++)
            for (int q = 0; q < 3; q++)
                rgb[q][i] = (int) Math.max(0, Math.min(255, ((rgb[q][i] / 255. - .5) * c + .5) * 255));

        // blur

        int w = input.getWidth();
        int h = input.getHeight();

        int k = 5;
        int kd = 2 * k + 1;
        double dd = 1 / Math.hypot(w / 2, h / 2);

        for (int reps = 0; reps < 5; reps++) {

            int tmp[][] = new int[3][pixels.length];
            int vmin[] = new int[Math.max(w, h)];
            int vmax[] = new int[Math.max(w, h)];

            for (int y = 0, yw = 0, yi = 0; y < h; y++) {
                int[] sum = new int[3];
                for (int i = -k; i <= k; i++) {
                    int ii = yi + Math.min(w - 1, Math.max(i, 0));
                    for (int q = 0; q < 3; q++)
                        sum[q] += rgb[q][ii];
                }
                for (int x = 0; x < w; x++) {

                    int dx = x - w / 2;
                    int dy = y - h / 2;
                    double dist = Math.sqrt(dx * dx + dy * dy) * dd;
                    dist *= dist;

                    for (int q = 0; q < 3; q++)
                        tmp[q][yi] = (int) Math.min(255, sum[q] / kd * dist + rgb[q][yi] * (1 - dist));

                    if (y == 0) {
                        vmin[x] = Math.min(x + k + 1, w - 1);
                        vmax[x] = Math.max(x - k, 0);
                    }

                    int p1 = yw + vmin[x];
                    int p2 = yw + vmax[x];

                    for (int q = 0; q < 3; q++)
                        sum[q] += rgb[q][p1] - rgb[q][p2];
                    yi++;
                }
                yw += w;
            }

            for (int x = 0, yi = 0; x < w; x++) {
                int[] sum = new int[3];
                int yp = -k * w;
                for (int i = -k; i <= k; i++) {
                    yi = Math.max(0, yp) + x;
                    for (int q = 0; q < 3; q++)
                        sum[q] += tmp[q][yi];
                    yp += w;
                }
                yi = x;
                for (int y = 0; y < h; y++) {

                    int dx = x - w / 2;
                    int dy = y - h / 2;
                    double dist = Math.sqrt(dx * dx + dy * dy) * dd;
                    dist *= dist;

                    for (int q = 0; q < 3; q++)
                        rgb[q][yi] = (int) Math.min(255, sum[q] / kd * dist + tmp[q][yi] * (1 - dist));

                    if (x == 0) {
                        vmin[y] = Math.min(y + k + 1, h - 1) * w;
                        vmax[y] = Math.max(y - k, 0) * w;
                    }
                    int p1 = x + vmin[y];
                    int p2 = x + vmax[y];

                    for (int q = 0; q < 3; q++)
                        sum[q] += tmp[q][p1] - tmp[q][p2];

                    yi += w;
                }
            }
        }

        // pseudo-lighting pass

        for (int i = 0; i < pixels.length; i++) {
            int dx = i % w - w / 2;
            int dy = i / w - h / 2;
            double dist = Math.sqrt(dx * dx + dy * dy) * dd;
            dist *= dist;

            for (int q = 0; q < 3; q++) {
                if (dist > 1 - .375)
                    rgb[q][i] *= 1 + (Math.sqrt((1 - dist + .125) / 2) - (1 - dist) - .125) * .7;
                if (dist < .375 || dist > .375)
                    rgb[q][i] *= 1 + (Math.sqrt((dist + .125) / 2) - dist - .125) * dist > .375 ? 1 : .8;
                rgb[q][i] = Math.min(255, Math.max(0, rgb[q][i]));
            }
        }

        // reassemble image

        BufferedImage output = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_ARGB);

        pixels = ((DataBufferInt) output.getData().getDataBuffer()).getData();

        for (int i = 0; i < pixels.length; i++)
            pixels[i] = 255 << 24 | rgb[0][i] << 16 | rgb[1][i] << 8 | rgb[2][i];

        output.setRGB(0, 0, output.getWidth(), output.getHeight(), pixels, 0, output.getWidth());

        // display results

        display(input, output);

        // output image

        ImageIO.write(output, "PNG", new File(args[0].substring(0, args[0].lastIndexOf('.')) + " miniaturized.png"));

    }

    private static int[][] toRGB(double[] h, double[] s, double[] v) {
        int[] r = new int[h.length];
        int[] g = new int[h.length];
        int[] b = new int[h.length];

        for (int i = 0; i < h.length; i++) {
            double C = v[i] * s[i];
            double H = h[i];
            double X = C * (1 - Math.abs(H % 2 - 1));

            double ri = 0, gi = 0, bi = 0;

            if (0 <= H && H < 1) {
                ri = C;
                gi = X;
            } else if (1 <= H && H < 2) {
                ri = X;
                gi = C;
            } else if (2 <= H && H < 3) {
                gi = C;
                bi = X;
            } else if (3 <= H && H < 4) {
                gi = X;
                bi = C;
            } else if (4 <= H && H < 5) {
                ri = X;
                bi = C;
            } else if (5 <= H && H < 6) {
                ri = C;
                bi = X;
            }

            double m = v[i] - C;

            r[i] = (int) ((ri + m) * 255);
            g[i] = (int) ((gi + m) * 255);
            b[i] = (int) ((bi + m) * 255);
        }

        return new int[][] { r, g, b };
    }

    private static double[][] toHSV(int[] c) {
        double[] h = new double[c.length];
        double[] s = new double[c.length];
        double[] v = new double[c.length];

        for (int i = 0; i < c.length; i++) {
            double r = (c[i] & 0xFF0000) >> 16;
            double g = (c[i] & 0xFF00) >> 8;
            double b = c[i] & 0xFF;

            r /= 255;
            g /= 255;
            b /= 255;

            double M = Math.max(Math.max(r, g), b);
            double m = Math.min(Math.min(r, g), b);
            double C = M - m;

            double H = 0;

            if (C == 0)
                H = 0;
            else if (M == r)
                H = (g - b) / C % 6;
            else if (M == g)
                H = (b - r) / C + 2;
            else if (M == b)
                H = (r - g) / C + 4;

            h[i] = H;
            s[i] = C / M;
            v[i] = M;
        }
        return new double[][] { h, s, v };
    }

    private static void display(final BufferedImage original, final BufferedImage output) {

        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int wt = original.getWidth();
        int ht = original.getHeight();
        double ratio = (double) wt / ht;
        if (ratio > 1 && wt > d.width / 2) {
            wt = d.width / 2;
            ht = (int) (wt / ratio);
        }
        if (ratio < 1 && ht > d.getHeight() / 2) {
            ht = d.height / 2;
            wt = (int) (ht * ratio);
        }

        final int w = wt, h = ht;

        JFrame frame = new JFrame();
        JPanel pan = new JPanel() {
            BufferedImage buffer = new BufferedImage(w * 2, h, BufferedImage.TYPE_INT_RGB);
            Graphics2D gg = buffer.createGraphics();

            {
                gg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            }

            @Override
            public void paint(Graphics g) {
                gg.drawImage(original, 0, 0, w, h, null);
                gg.drawImage(output, w, 0, w, h, null);
                g.drawImage(buffer, 0, 0, null);
            }
        };
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pan.setPreferredSize(new Dimension(w * 2, h));
        frame.setLayout(new BorderLayout());
        frame.add(pan, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}

8

জে

এটি একটি দুর্দান্ত চ্যালেঞ্জ ছিল। অস্পষ্টতা, স্যাচুরেশন এবং বৈসাদৃশ্যগুলির জন্য সেটিংস কঠোর কোডেড তবে ইচ্ছে করলে সহজেই পরিবর্তন করা যায়। তবে ফোকাসের ক্ষেত্রটি কেন্দ্রের মধ্যে একটি অনুভূমিক রেখা হিসাবে হার্ড-কোডড। অন্যান্য সেটিংসের মতো এটি কেবল পরিবর্তন করা যায় না। এটি বেশিরভাগ পরীক্ষার চিত্রগুলি কোনও শহর জুড়ে দর্শনের বৈশিষ্ট্যগুলির কারণে বেছে নেওয়া হয়েছিল।

গাউসিয়ান অস্পষ্টতার পরে আমি চিত্রটি অনুভূমিকভাবে 5 টি অঞ্চলে বিভক্ত করেছি। শীর্ষ এবং নীচের অঞ্চলগুলি অস্পষ্টতার 100% গ্রহণ করবে। মধ্য অঞ্চলটি অস্পষ্টতার 0% পাবে। দুটি অবশিষ্ট অঞ্চল উভয়ই 0% থেকে 100% পর্যন্ত বিপরীত ঘনক্ষেত্রে আনুপাতিকভাবে স্কেল করবে।

কোডটি স্ক্রিপ্ট হিসাবে জেতে ব্যবহার করতে হবে এবং সেই স্ক্রিপ্টটি একই ফোল্ডারে input.bmpথাকবে যা ইনপুট চিত্র হবে। এটি তৈরি করবে output.bmpযা ইনপুটটির একটি নকল ক্ষুদ্রাকরণ হবে ।

পারফরম্যান্সটি ভাল এবং আমার পিসিতে একটি আই 7-7770০ ক ব্যবহার করে, ওপির সেট থেকে কোনও চিত্র প্রক্রিয়া করতে প্রায় 20 সেকেন্ড সময় লাগে। পূর্বে, ;._3সাবহারে অপারেটরের সাথে মানক কনভোলিউশন ব্যবহার করে কোনও চিত্র প্রক্রিয়া করতে প্রায় 70 সেকেন্ড সময় নিয়েছিল । সমঝোতা সঞ্চালনের জন্য এফএফটি ব্যবহার করে পারফরম্যান্সটি উন্নত হয়েছিল।

লুপ লুপ-মিনি শহর সিটি-মিনি

এই কোড প্রয়োজন bmpএবং math/fftwঅ্যাডঅনস ইনস্টল করার জন্য। ব্যবহার করে আপনি সেগুলি ইনস্টল করতে পারেন install 'bmp'এবং install 'math/fftw'। আপনার সিস্টেমে fftwলাইব্রেরি ইনস্টল করার প্রয়োজনও থাকতে পারে।

load 'bmp math/fftw'

NB. Define 2d FFT
fft2d =: 4 : 0
  s =. $ y
  i =. zzero_jfftw_ + , y
  o =. 0 * i
  p =. createplan_jfftw_ s;i;o;x;FFTW_ESTIMATE_jfftw_
  fftwexecute_jfftw_ p
  destroyplan_jfftw_ p
  r =. s $ o
  if. x = FFTW_BACKWARD_jfftw_ do.
    r =. r % */ s
  end.
  r
)

fft2 =: (FFTW_FORWARD_jfftw_ & fft2d) :. (FFTW_BACKWARD_jfftw & fft2d)
ifft2 =: (FFTW_BACKWARD_jfftw_ & fft2d) :. (FFTW_FORWARD_jfftw & fft2d)

NB. Settings: Blur radius - Saturation - Contrast
br =: 15
s =: 3
c =: 1.5

NB. Read image and extract rgb channels
i =: 255 %~ 256 | (readbmp 'input.bmp') <.@%"_ 0 ] 2 ^ 16 8 0
'h w' =: }. $ i

NB. Pad each channel to fit Gaussian blur kernel
'hp wp' =: (+: br) + }. $ i
ip =: (hp {. wp {."1 ])"_1 i

NB. Gaussian matrix verb
gm =: 3 : '(%+/@,)s%~2p1%~^(s=.*:-:y)%~-:-+&*:/~i:y'

NB. Create a Gaussian blur kernel
gk =: fft2 hp {. wp {."1 gm br

NB. Blur each channel using FFT-based convolution and unpad
ib =: (9 o. (-br) }. (-br) }."1 br }. br }."1 [: ifft2 gk * fft2)"_1 ip

NB. Create the blur gradient to emulate tilt-shift
m =: |: (w , h) $ h ({. >. (({.~ -)~ |.)) , 1 ,: |. (%~i.) 0.2 I.~ (%~i.) h

NB. Tilt-shift each channel
it =: i ((m * ]) + (-. m) * [)"_1 ib

NB. Create the saturation matrix
sm =: |: ((+ ] * [: =@i. 3:)~ 3 3 |:@$ 0.299 0.587 0.114 * -.) s

NB. Saturate and clamp
its =: 0 >. 1 <. sm +/ .*"1 _ it

NB. Contrast and clamp
itsc =: 0 >. 1 <. 0.5 + c * its - 0.5

NB. Output the image
'output.bmp' writebmp~ (2 <.@^ 16 8 0) +/ .* 255 <.@* itsc

exit ''
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.