「色使いまねフィルタ2」の編集履歴(バックアップ)一覧に戻る

色使いまねフィルタ2 - (2010/07/04 (日) 14:07:37) のソース

テスト
プログラム製作者 兵庫県加古川市加古川町南備後79-16 堀江伸一

&ref(色まねフィルタ.bmp)
右上がイラストA、左上がイラストBのうち使われている色をヒストグラフに取ったものとし、RGの色分布とする。
イラストAのRGの色が特に密集しているところの色を、イラストBの色が密集しているところに移動する処理を実装したい。

つまりイラストBの色使いでイラストAの色を塗りなおすという感じ。

ただ今アルゴリズム思考中。
結構古典的な処理だと思うので、調べればなにか見つかると思うのだけど?
減色処理との違いは、色を移動するだけなので、色数自体を減らしたいわけじゃないという点。

適当でいいなら難しくはなさそうだけど、手順が少しめんどくさそう。

普遍的な処理法があるなら、それでいきたいけど、そちらは少し難しそう?




*1 XY軸をRGに、RGの使われている回数をZ軸にとれば色のヒストグラフを取れば山並のようなものが見えてくる。
*2 山の頂に当たるところをサーチすれば島の山頂が見つかる。
*3 山頂から探索し、一定値以上の場所を探せば島のようなものがでてくるから後は島ごとにらべリング処理をすれば、島がみつかるはず?
*4  この概念をRGBに拡張すると良い

 

上記概念に基づき、作りかけのフィルタを掲載。
FormにPictureBox2個、ボタン3個 C#で稼動。
Pixiv登録yamasushiさんにアドバイスをもらって堀江伸一が製作中。

&ref(色まねフィルタ覚描きイラスト.bmp)


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
public delegate void ExampleCallback(Bitmap outBit, PictureBox p1);

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        int tc = 0;
        //Bitmap lastB;
        public Form1()
        {
            InitializeComponent();

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            pictureBox2.Image = Image.FromFile("D:/色々/中高生向け戦争小説 ギガンダム討伐/tumblr_l0771pDcX01qbq8jdo1_500.jpg");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap b1 = new Bitmap(pictureBox1.Image);
            
            Bitmap b2 = new Bitmap(pictureBox2.Image);
            



            //pictureBox1.Image  =b1;

            pictFilter PTC1 = new WindowsFormsApplication2.pictFilter();
            PTC1.Color_SandPlay_Filter(b1,b2,30);
            

            //pict_RGB_And_Deviation aveDev = new pict_RGB_And_Deviation(150, 150, 150, 70, 70, 70);
            //上記メソッドは
            //b1 = PTC1.cercleChange(b1);
            //b2 = PTC1.cercleChange(b2);
            //pictureBox1.Image = b2;
            //pictureBox1.Image = b2;  
            //b2= PTC1.standard_deviation_filter(b1, b2);
            //pictureBox1.Image = b2;
            //pictureBox1.Image= PTC1.Color_imitation_filter2(b1,b2,15);

            //pictureBox1.Image = PTC1.standard_deviation_filter(aveDev, b2);
            //pictureBox1.Image  =PTC1.lineFilter(b1);
            //b1=PTC1.lineFilter(b1);

            /*pictFilter PTC = new WindowsFormsApplication2.pictFilter(PTC1.lineFilter (b1), new ExampleCallback(ResultCallback),pictureBox1);
            Thread t1 =new Thread(new ThreadStart(PTC.cercleChange));
            t1.Start();
            t1.Join();
            */
            //pictFilter PTC = new WindowsFormsApplication2.pictFilter();
            //pictureBox1.Image = PTC.lineFilter(b1);
            //pictureBox1.Image = PTC.flatFilter2( PTC.cercleChange      (b1)) ;
            //b1.Dispose();
        }
        public static void ResultCallback(Bitmap outBit, PictureBox p1)
        {
            p1.Image = outBit;

        }


        private void pictureBox1_Click(object sender, EventArgs e)
        {
            tc++;
            pictureBox1.Top = 0;
            pictureBox1.Left = 0;

        }

        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "画像ファイル(*.jpeg;*.jpg;*.gif)|*.jpeg;*.jpg;*.gif|すべてのファイル(*.*)|*.*";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                pictureBox2.Image = Image.FromFile(ofd.FileName); 
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "画像ファイル(*.jpeg;*.jpg;*.gif)|*.jpeg;*.jpg;*.gif|すべてのファイル(*.*)|*.*";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                pictureBox1.Image = Image.FromFile(ofd.FileName);
            }
        }

    }
    class pictFilter
    {
        Random rnd = new Random();
        Bitmap pictOut = null;
        int h;//絵の高さ
        int w;//絵の横幅
        Bitmap pictIn;
        ExampleCallback callback;
        PictureBox lastPict;
        cell[, ,] cells;
        cell[, ,] cells2;
        int cell_size;
        int size;
        int id=0;//再帰関数で使うための名札付け
        public pictFilter()
        {
            h = 0;
            w = 0;
        }





        public Bitmap Color_SandPlay_Filter(Bitmap b1, Bitmap b2, int c_size)
        {
            cell_size = c_size;
            size = 255 / cell_size + 2;
            cells = new cell[size, size, size];
            cells2 = new cell[size, size, size];

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    for (int k = 0; k < size; k++)
                    {
                        cells[i, j, k] = new cell();
                        cells2[i, j, k] = new cell();
                    }
                }
            }
            Color C1, C2;
            Bitmap b3 = new Bitmap(b2.Width, b2.Height);
            //List<cell> cell_list = new List<cell>(); //


            //Color_SandPlay_Filterメソッド
            for (int i = 0; i < b1.Width; i++)
            {
                for (int j = 0; j < b1.Height; j++)
                {
                    C1 = b1.GetPixel(i, j);
                    cells[get_cell_point1(C1.R), get_cell_point1(C1.G), get_cell_point1(C1.B)].add(C1.R, C1.G, C1.B);
                }
            }

            for (int i = 0; i < b2.Width; i++)
            {
                for (int j = 0; j < b2.Height; j++)
                {
                    C2 = b2.GetPixel(i, j);
                    cells2[get_cell_point1(C2.R), get_cell_point1(C2.G), get_cell_point1(C2.B)].add(C2.R, C2.G, C2.B);
                }
            }
            //Color_SandPlay_Filterメソッド
            //砂山遊びの局地的な山頂を求める処理
            List<cell> maximun_cell_list = new List<cell>(); //
            List<cell> maximun_cell_list2 = new List<cell>(); //
            List<cellPoint> cellPoints1 = new List<cellPoint>();
            List<cellPoint> cellPoints2 = new List<cellPoint>();
            
            for (int i = 1; i < size-1; i++)
            {
                for (int j = 1; j < size-1; j++)
                {
                    for (int k = 1; k < size-1; k++)
                    {
                        if (check_local_maximun(ref cells, i, j, k) == true)
                        {
                            maximun_cell_list.Add(cells[i, j, k]);
                            cellPoints1.Add(new cellPoint(i, j, k));
                        }
                        if (check_local_maximun(ref cells2, i, j, k) == true)
                        {
                            maximun_cell_list2.Add(cells2[i, j, k]);
                            cellPoints2.Add(new cellPoint(i, j, k)); 
                        }
                    }
                }
            }
            id = 1;
            cellPoint cP;
            cell mCell;
            cell aveCell = new cell();
            List<cell> IdCellAveList = new List<cell>(); 
            for(int i=0;i<maximun_cell_list.Count;i++  ){
                cP=cellPoints1[i];
                mCell=maximun_cell_list[i] ;
                aveCell = new cell();
                aveCell.id = id;
                search_Cells(ref cells, cP.rPoint, cP.gPoint, cP.bPoint,mCell.getCount()+1,ref aveCell);
                IdCellAveList.Add(aveCell);
                id++;
            }
            id = 1;
            
            
            List<cell> IdCellAveList2 = new List<cell>(); 
            for (int i = 0; i < maximun_cell_list2.Count; i++)
            {
                cP = cellPoints2[i];
                mCell = maximun_cell_list2[i];
                aveCell = new cell();
                aveCell.id = id; 
                search_Cells(ref cells2, cP.rPoint, cP.gPoint, cP.bPoint, mCell.getCount(),ref aveCell);
                IdCellAveList2.Add(aveCell); 
                id++;
            }

            IdCellAveList2.Sort(delegate(cell x, cell y)
            {
                return y.getCount() - x.getCount();
            });
            IdCellAveList.Sort(delegate(cell x, cell y)
            {
                return y.getCount() - x.getCount();
            });

            int sabunT=IdCellAveList.Count() - IdCellAveList2.Count();
            
            //1が加工されるデータ、2が教師データとなっている
            //f(1)→2な写像を取る
            if(sabunT <0){
                IdCellAveList2.RemoveRange(IdCellAveList.Count(), Math.Abs(sabunT)); 
            }
            List<cellIDAveAndDev> IDAveAndDev =new List<cellIDAveAndDev>() ;
            List<cellIDAveAndDev> IDAveAndDev2 = new List<cellIDAveAndDev>();
            for (int i = 0; i < IdCellAveList.Count; i++)
            {
                IDAveAndDev.Add (cacl_id_dev( ref cells, IdCellAveList[i]));
                IDAveAndDev2.Add(cacl_id_dev (ref cells2, IdCellAveList[i]));
            }

            return b3;
        }


        public cellIDAveAndDev cacl_id_dev(ref cell [,,] cells ,cell mycell)
        {
               cellIDAveAndDev  cellAveAndDev = new cellIDAveAndDev (mycell.id);
               cellAveAndDev.setAve (  mycell.aveColor());
               cell Cell1=new cell() ;

                double RDev=0;
                double GDev=0;
                double BDev=0;
                double RAve = cellAveAndDev.aveR  ;
                double GAve = cellAveAndDev.aveG  ;
                double BAve = cellAveAndDev.aveB  ;
                double CT;
            Color C1=new Color() ;
               for (int i = 1; i < size - 1; i++)
               {
                   for (int j = 1; j < size - 1; j++)
                   {
                       for (int k = 1; k < size - 1; k++)
                       {
                           Cell1 =cells[i, j, k];
                           if (Cell1.id == mycell.id)
                           {
                               C1=Cell1.aveColor();
                               CT=Cell1.getCount();
                               RDev+=(C1.R - RAve) * (C1.R - RAve) * CT;
                               GDev += (C1.G - GAve) * (C1.G - GAve) * CT;
                               BDev += (C1.B - BAve) * (C1.B - BAve) * CT;
                           }
                       }
                   }
               }
               cellAveAndDev.devR   =   Math.Sqrt(RDev / mycell.getCount());
               cellAveAndDev.devG   =   Math.Sqrt(GDev / mycell.getCount());
               cellAveAndDev.devB   =   Math.Sqrt(BDev / mycell.getCount());
               return cellAveAndDev; 
        }
            

        public void search_Cells(ref cell[,,] myCells, int rPoint,int gPoint,int bPoint,int oldCount,ref cell c){
            //再帰関数Color_SandPlay_Filterで使う
            if (rPoint == 0 || gPoint == 0 || bPoint == 0)
            {
                return;
            }
            if (rPoint >= size-1 || gPoint >= size-1 || bPoint >= size-1)
            {
                return;
            }
            cell mycell = myCells[rPoint, gPoint, bPoint];
            int myCount=mycell.getCount(); 
            if (myCount <= oldCount && myCount>0 && mycell.id==0 )
            {
                mycell.id = id;
                c.add(mycell);
                search_Cells(ref myCells,   rPoint + 1, gPoint      , bPoint    , myCount,ref c);
                search_Cells(ref myCells,   rPoint - 1, gPoint      , bPoint    , myCount,ref c);
                search_Cells(ref myCells,   rPoint,     gPoint + 1  , bPoint    , myCount,ref c);
                search_Cells(ref myCells,   rPoint,     gPoint - 1  , bPoint    , myCount,ref c);
                search_Cells(ref myCells,   rPoint,     gPoint      , bPoint + 1, myCount,ref c);
                search_Cells(ref myCells,   rPoint,     gPoint      , bPoint - 1, myCount,ref c);
            }
        }

        public bool check_local_maximun(ref cell[,,] mycell,int rPoint,int gPoint,int bPoint)
        {
            if (rPoint == 0 || gPoint == 0 || bPoint == 0)
            {
                return false;
            }
            if (rPoint >= size-1 || gPoint >= size-1 || bPoint >= size-1)
            {
                return false;
            }
            int u = mycell[rPoint + 1  , gPoint    , bPoint     ].getCount() ;
            int d = mycell[rPoint - 1  , gPoint    , bPoint     ].getCount() ;
            int l = mycell[rPoint      , gPoint+1  , bPoint     ].getCount();
            int r = mycell[rPoint      , gPoint-1  , bPoint     ].getCount();
            int f = mycell[rPoint      , gPoint    , bPoint+1   ].getCount();
            int b = mycell[rPoint      , gPoint    , bPoint-1   ].getCount();
            int c = mycell[rPoint, gPoint, bPoint].getCount() ;
            if (c > u && c > d && c > l && c > r && c > f && c > b && c>10)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public int get_cell_point1(int rgb)
        {
            return (rgb / cell_size) + 1;
        }

















        public double colorLen2(Color C1, Color C2)
        {
           return  (C1.R - C2.R) * (C1.R - C2.R) + (C1.G - C2.G) * (C1.G - C2.G) + (C1.B - C2.B) * (C1.B - C2.B);
        }

        public int get_cell_point(int rgb)
        {
            return (rgb / cell_size) +2; 
        }
      






        public pictFilter(Bitmap b1, ExampleCallback callbackDelegate, PictureBox p1)
        {
            this.pictIn = b1;
            h = 0;
            w = 0;
            callback = callbackDelegate;
            lastPict = p1;
        }


        private int cutNum(int min, int max, int t)
        {
            if (t < min)
            {
                t = min;
            }
            if (t > max)
            {
                t = max;
            }
            return t;
        }

    }


    public class cell
    {
        public int sumR = 0;
        public int sumG = 0;
        public int sumB = 0;
        int count = 0;
        public int id=0;//再起関数で使うための変数、ラベリング処理用
        public int getCount()
        {
            return count;
        }

        public void add(int r, int g, int b)
        {
            count++;
            sumR += r;
            sumG += g;
            sumB += b;
        }
        public void add(Color C)
        {
            count++;
            sumR += C.R;
            sumG += C.G;
            sumB += C.B;

        }
        public void add(cell c)
        {
            count += c.getCount();
            sumR += c.sumR;
            sumG += c.sumG;
            sumB += c.sumB;
        }


        public Color aveColor()
        {
            if (count > 0)
            {
                

                return Color.FromArgb(
                    (int)sumR/count,
                    (int)sumG/count,
                    (int)sumB/count) ;
            }else{
                return (Color.FromArgb(0,0,0) );
            }
        }
    }
    
    public class cellPoint
    {
        public  int rPoint;
        public  int gPoint;
        public  int bPoint;

        public  cellPoint(int r,int g,int b){
            rPoint = r;
            gPoint = g;
            bPoint = b;
        }

        
    }

    public class cellIDAveAndDev{
        public int aveR=0;
        public int aveG=0;
        public int aveB=0;
        public double devR=0;
        public double devG=0;
        public double devB=0;
        public int id;
        public cellIDAveAndDev(int myid)
        {
            id=myid ;
        }
        public void setAve(Color C){
            aveR = C.R;
            aveG = C.G;
            aveB = C.B;
        }
    }
}