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

色使いまねフィルタ - (2010/06/24 (木) 19:20:42) のソース

C#プログラム
製作者 堀江伸一
[[色使いまねフィルタ2]]

pictureBox2つ、ボタン3つおいて使うサンプルフィルタ。

ボタン2を押すとダイアログが出るので、フィルタの教師データとなる画像を選択。
ボタン3も押すと、フィルタが適用される画像が準備される。


ボタン1を押すと、フィルタが適用される。
ボタン1を押すと、ボタン3で用意した画像からカラーテーブルが作成され、フィルタされる画像をそのカラーテーブルに近づける処理が実行される。







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:/色々/中高生向け戦争小説 ギガンダム討伐/11033455_m.jpg");
        }

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



            //pictureBox1.Image  =b1;

            pictFilter PTC1 = new WindowsFormsApplication2.pictFilter();
            //pict_RGB_And_Deviation aveDev = new pict_RGB_And_Deviation(150, 150, 150, 70, 70, 70);
            //上記メソッドは
            //b2 = PTC1.cercleChange(b2);
            //b1 = PTC1.cercleChange(b1);
   
            //pictureBox1.Image = b2;  
            pictureBox1.Image= PTC1.Color_imitation_filter(b1,b2,10);

            //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;
        int cell_size;
        public pictFilter()
        {
            h = 0;
            w = 0;
        }


        public Bitmap Color_imitation_filter(Bitmap b1, Bitmap b2,int c_size)
        {
            cell_size = c_size;
            int size=255/cell_size+5;
            cells = 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();
                    }
                }
            }

            pict_RGB_And_Deviation aveDev1=new pict_RGB_And_Deviation(b1);
            pict_RGB_And_Deviation aveDev2 = new pict_RGB_And_Deviation(b2);

            int sabunR =(int)Math.Floor ( aveDev1.aveR - aveDev2.aveR);
            int sabunG =(int)Math.Floor ( aveDev1.aveG - aveDev2.aveG);
            int sabunB = (int)Math.Floor(aveDev1.aveB - aveDev2.aveB);    

            Color C1;
            Bitmap b3=new Bitmap (b2.Width,b2.Height );
            for (int i = 0; i < b1.Width; i++)
            {
                for (int j = 0; j < b1.Height; j++)
                {
                    C1 = b1.GetPixel(i, j);
                   
                    cells[get_cell_point(C1.R), get_cell_point(C1.G), get_cell_point(C1.B)].add(C1.R, C1.G, C1.B);
                }
            }
            Color nextColor;
            


            for (int i = 0; i < b2.Width; i++)
            {
                for (int j = 0; j < b2.Height; j++)
                {
                    C1 = b2.GetPixel(i, j);
                    //nextColor=C1;
                    nextColor =Color.FromArgb(cutNum(0, 255, C1.R + sabunR/2),
                        cutNum(0, 255, C1.G + sabunG/2),
                        cutNum(0, 255, C1.B + sabunB/2));
                    //nextColor = getAveCountCell(nextColor);
                    nextColor  = getMaxCountCell(nextColor);
                    //
                    b3.SetPixel(i, j, nextColor); 
                }
            }


                return b3;
        }


        public Color getAveCountCell(Color C1)
        {
            List<cell> cell_list = new List<cell>(); //
            int rPoint, gPoint, bPoint;
            cell myCell;
            //Count数の比率からセルを平均的に返す処理
            rPoint = get_cell_point(C1.R);
            gPoint = get_cell_point(C1.G);
            bPoint = get_cell_point(C1.B);
            int sumCount=0;

            for (int i = -2; i < 3; i++)
            {
                for (int j = -2; j < 3; j++)
                {
                    for (int k = -2; k < 3; k++)
                    {
                        myCell = cells[rPoint+i, gPoint+j, bPoint+k];
                        
                        if (myCell.getCount() > 0)
                        {
                            cell_list.Add(myCell);
                            sumCount  +=myCell.getCount(); 
                        }
                    }
                }
            }

            if (cell_list.Count > 0)
            {
                int rndC=rnd.Next(sumCount);
                int tSum=0;
                Color C2=C1;
                foreach (cell myCell1 in cell_list)
                {
                    tSum +=myCell1.getCount();  
                    if(tSum>rndC){
                        C2=myCell1.aveColor() ;
                        break;
                    }
                }
                
                
                
                
                return Color.FromArgb(
                    (int)Math.Floor(C2.R * 0.1d + C1.R * 0.9d),
                    (int)Math.Floor(C2.G * 0.1d + C1.G * 0.9d),
                    (int)Math.Floor(C2.B * 0.1d + C1.B * 0.9d)
                    );
            }
            else
            {
                return C1;
            }

        }
        
        public Color getMaxCountCell(Color C1)
        {
            List<cell> cell_list = new List<cell>(); //
            int maxCount = 1;
            int rPoint,gPoint,bPoint;
            cell myCell;
            //Countが最も大きいセルを返す処理
            rPoint=get_cell_point(C1.R );  
            gPoint=get_cell_point(C1.G);
            bPoint=get_cell_point (C1.B);
            for (int i = -2; i < 3; i++)
            {
                for (int j = -2; j < 3; j++)
                {
                    for (int k = -2; k < 3; k++)
                    {
                        myCell=cells[rPoint+i,gPoint+j,bPoint+k]; 
                        if(myCell.getCount ()>maxCount ){
                            cell_list.Clear();
                            cell_list.Add(myCell);
                            maxCount = myCell.getCount(); 
                        }else if(myCell.getCount ()==maxCount ){
                            cell_list.Add(myCell);
                        }

                    }
                }
            }

            if (cell_list.Count>0)
            {                
                Color C2;
                C2=cell_list[rnd.Next(cell_list.Count)].aveColor()  ;

                return Color.FromArgb(
                    (int)Math.Floor (C2.R * 0.8d + C1.R * 0.2d),
                    (int)Math.Floor (C2.G * 0.8d + C1.G * 0.2d),
                    (int)Math.Floor (C2.B * 0.8d + C1.B * 0.2d)
                    ); 
            }
            else
            {
                return C1;
            }
            
        }



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

        public Bitmap standard_deviation_filter(pict_RGB_And_Deviation aveDev1, Bitmap b2)
        {
            Color C2;
            Bitmap outBit;
            double tR, tG, tB;
            int tR1, tG1, tB1;
            pict_RGB_And_Deviation aveDev2 = new pict_RGB_And_Deviation(b2);

            outBit = new Bitmap(b2.Width, b2.Height);

            for (int i = 0; i < b2.Width; i++)
            {
                for (int j = 0; j < b2.Height; j++)
                {
                    C2 = b2.GetPixel(i, j);
                    //tR = ((C2.R - aveDev2.aveR) / aveDev2.devR) * ((C2.R - aveDev2.aveR) / aveDev2.devR) * aveDev1.devR + aveDev1.aveR;
                    //tG = ((C2.G - aveDev2.aveG) / aveDev2.devG) * (C2.G - aveDev2.aveG) / aveDev2.devG * aveDev1.devG + aveDev1.aveG;
                    //tB = ((C2.B - aveDev2.aveB) / aveDev2.devB) * (C2.B - aveDev2.aveB) / aveDev2.devB * aveDev1.devB + aveDev1.aveB;

                    tR = Math.Log(3 * ((C2.R - aveDev2.aveR) / aveDev2.devR)) * aveDev1.devR + aveDev1.aveR;
                    tG = Math.Log(3 * ((C2.G - aveDev2.aveG) / aveDev2.devG)) * aveDev1.devG + aveDev1.aveG;
                    tB = Math.Log(3 * ((C2.B - aveDev2.aveB) / aveDev2.devB)) * aveDev1.devB + aveDev1.aveB;
                    
                    /*
                    tR = (C2.R - aveDev2.aveR);
                    tR = tR / 2.0 + 0.5;
                    if (tR > 0.5)
                    {
                        tR = -Math.Pow(2 * tR - 2, 0.7) / 2 + 1;
                    }
                    else
                    {
                        tR=2 * Math.Pow(tR, 0.7/2);
                    }
                    tR = tR * 2 - 1;
                    */
                    
                    
                    tR1 = cutNum(0, 255, (int)Math.Floor(tR));
                    tG1 = cutNum(0, 255, (int)Math.Floor(tG));
                    tB1 = cutNum(0, 255, (int)Math.Floor(tB));
                    outBit.SetPixel(i, j, Color.FromArgb(tR1, tG1, tB1));

                }
            }
            //生物の遺伝子構造解析をして病気対策をするとき、遺伝子コードのパターンマッチにパソコンを使うとか、本当はそういうプログラム書けたらなと思ったり、

            return outBit;
        }

        public Bitmap standard_deviation_filter(Bitmap b1, Bitmap b2)
        {
            Color C2;
            Bitmap outBit;
            double tR, tG, tB;
            int tR1, tG1, tB1;
            pict_RGB_And_Deviation aveDev1 = new pict_RGB_And_Deviation(b1);
            pict_RGB_And_Deviation aveDev2 = new pict_RGB_And_Deviation(b2);

            outBit = new Bitmap(b2.Width, b2.Height);

            for (int i = 0; i < b2.Width; i++)
            {
                for (int j = 0; j < b2.Height; j++)
                {
                    C2 = b2.GetPixel(i, j);
                    tR = ((C2.R - aveDev2.aveR) / aveDev2.devR) * aveDev1.devR + aveDev1.aveR;
                    tG = (C2.G - aveDev2.aveG) / aveDev2.devG * aveDev1.devG + aveDev1.aveG;
                    tB = (C2.B - aveDev2.aveB) / aveDev2.devB * aveDev1.devB + aveDev1.aveB;
                    //tR = ((C2.R - aveDev2.aveR) / aveDev2.devR) * ((C2.R - aveDev2.aveR) / aveDev2.devR) * aveDev1.devR + aveDev1.aveR;
                    //tG = ((C2.G - aveDev2.aveG) / aveDev2.devG) * ((C2.G - aveDev2.aveG) / aveDev2.devG) * aveDev1.devG + aveDev1.aveG;
                    //tB = ((C2.B - aveDev2.aveB) / aveDev2.devB) * ((C2.B - aveDev2.aveB) / aveDev2.devB) * aveDev1.devB + aveDev1.aveB;
                    

                    tR1 = cutNum(0, 255, (int)Math.Floor(tR));
                    tG1 = cutNum(0, 255, (int)Math.Floor(tG));
                    tB1 = cutNum(0, 255, (int)Math.Floor(tB));
                    outBit.SetPixel(i, j, Color.FromArgb(tR1, tG1, tB1));

                }
            }
            //生物の遺伝子構造解析をして病気対策をするとき、遺伝子コードのパターンマッチにパソコンを使うとか、本当はそういうプログラム書けたらなと思ったり、

            return outBit;
        }






        public pictFilter(Bitmap b1, ExampleCallback callbackDelegate, PictureBox p1)
        {
            this.pictIn = b1;
            h = 0;
            w = 0;
            callback = callbackDelegate;
            lastPict = p1;
        }
        public Bitmap cercleChange(Bitmap b1)
        {
            //各ピクセルの色空間内の位置を点(ccR,ccB,ccG)を中心に体積拡大する処理
            //このメソッドはスレッドで呼ぶこと前提にしている
            float ccR = 128;
            float ccG = 128;
            float ccB = 128;
            float a = 2.0f;
            float b = 0.5f;
            double cR, cG, cB;
            double r1 = 0;
            double r2 = 0;
            Color C1;
            //double rk;

            this.h = b1.Height;
            this.w = b1.Width;
            Bitmap pictOut = new Bitmap(this.w, this.h);
            //Threadをとめる処理

            for (int i = 0; i < this.w; i++)
            {
                for (int j = 0; j < this.h; j++)
                {
                    C1 = b1.GetPixel(i, j);
                    r1 = Math.Sqrt((C1.R - ccR) * (C1.R - ccR) +
                        (C1.G - ccG) * (C1.G - ccG) +
                        (C1.B - ccB) * (C1.B - ccB)) / 255;

                    r2 = (a * r1 + b);
                    cR = r2 * (C1.R - ccR) + ccR;
                    cG = r2 * (C1.G - ccG) + ccG;
                    cB = r2 * (C1.B - ccB) + ccB;


                    pictOut.SetPixel(i, j,
                        Color.FromArgb(
                        cutNum(0, 255, (int)(cR)),
                        cutNum(0, 255, (int)(cG)),
                        cutNum(0, 255, (int)(cB))));
                    //これはLispではありませんw
                }
            }



            //テンプレ
            //this.h = pictIn.Height;
            //this.w = pictIn.Width;
            //pictOut = new Bitmap(this.w, this.h);
            //for(int i=0;i<this.w;i++){
            //    for (int j = 0; j < this.h; j++)
            //    {   
            //    }
            //}
            return pictOut;
        }
        public void cercleChange()
        {
            //各ピクセルの色空間内の位置を点(ccR,ccB,ccG)を中心に体積拡大する処理
            //このメソッドはスレッドで呼ぶこと前提にしている
            float ccR = 128;
            float ccG = 128;
            float ccB = 128;
            float a = 2.0f;
            float b = 0.5f;
            double cR, cG, cB;
            double r1 = 0;
            double r2 = 0;
            Color C1;
            //double rk;

            this.h = pictIn.Height;
            this.w = pictIn.Width;
            pictOut = new Bitmap(this.w, this.h);
            //Threadをとめる処理

            for (int i = 0; i < this.w; i++)
            {
                for (int j = 0; j < this.h; j++)
                {
                    C1 = pictIn.GetPixel(i, j);
                    r1 = Math.Sqrt((C1.R - ccR) * (C1.R - ccR) +
                        (C1.G - ccG) * (C1.G - ccG) +
                        (C1.B - ccB) * (C1.B - ccB)) / 255;

                    r2 = (a * r1 + b);
                    cR = r2 * (C1.R - ccR) + ccR;
                    cG = r2 * (C1.G - ccG) + ccG;
                    cB = r2 * (C1.B - ccB) + ccB;


                    pictOut.SetPixel(i, j,
                        Color.FromArgb(
                        cutNum(0, 255, (int)(cR)),
                        cutNum(0, 255, (int)(cG)),
                        cutNum(0, 255, (int)(cB))));
                    //これはLispではありませんw
                }
                if (i % 10 == 0)
                {
                    Thread.Sleep(30);
                }
            }
            //スレッドのOutput用命令
            callback(pictOut, lastPict);



            //テンプレ
            //this.h = pictIn.Height;
            //this.w = pictIn.Width;
            //pictOut = new Bitmap(this.w, this.h);
            //for(int i=0;i<this.w;i++){
            //    for (int j = 0; j < this.h; j++)
            //    {   
            //    }
            //}
            //return pictOut;
        }
        public Bitmap flatFilter2(Bitmap pictIn)
        {
            //色空間内の点の色座標をを法線ベクトル(1,1,1),rgbAve=r+g+bとなる平面から遠くへ引き離したり、近づけたりする処理
            Color C1;
            this.h = pictIn.Height;
            this.w = pictIn.Width;
            double flatLen = 0;
            double r1 = 0;

            float rgbAve = 256;
            pictOut = new Bitmap(this.w, this.h);
            double a = -1.0;
            double b = 2.0;
            double root3 = Math.Sqrt(3);
            double v1 = 184;
            double maxRGB = 0, minRGB = 0;

            for (int i = 0; i < this.w; i++)
            {
                for (int j = 0; j < this.h; j++)
                {
                    C1 = pictIn.GetPixel(i, j);
                    flatLen = (C1.R + C1.G + C1.B - rgbAve) / (root3); //点と平面までの距離
                    r1 = Math.Sign(flatLen) * ((a * Math.Abs(flatLen) / v1 + b));//点と平面までの距離に基づいて、次の点の平面からの距離を決定する。
                    maxRGB = Math.Max(C1.R + r1 * v1, Math.Max(C1.G + r1 * v1, C1.B + r1 * v1));
                    if (maxRGB > 255)
                    {
                        if (C1.R > C1.G && C1.R > C1.B)
                        {
                            r1 = r1 - (255 - C1.R) / v1 - 1;
                        }
                        else if (C1.G > C1.R && C1.G > C1.B)
                        {
                            r1 = r1 - (255 - C1.G) / v1 - 1;
                        }
                        else
                        {
                            r1 = r1 - (255 - C1.B) / v1 - 1;
                        }
                    }
                    minRGB = Math.Min(C1.R + r1 * v1, Math.Min(C1.G + r1 * v1, C1.B + r1 * v1));
                    if (minRGB < 0)
                    {
                        if (C1.R < C1.G && C1.R < C1.B)
                        {
                            r1 = r1 - (C1.R) / v1 - 1;
                        }
                        else if (C1.G < C1.R && C1.G < C1.B)
                        {
                            r1 = r1 - (C1.G) / v1 - 1;
                        }
                        else
                        {
                            r1 = r1 - (C1.B) / v1 - 1;
                        }
                    }


                    pictOut.SetPixel(i, j, Color.FromArgb(
                        cutNum(0, 255, (int)(C1.R + r1 * v1)),
                        cutNum(0, 255, (int)(C1.G + r1 * v1)),
                        cutNum(0, 255, (int)(C1.B + r1 * v1))));
                }
            }
            return pictOut;
        }


        public Bitmap adsorptionFilter(Bitmap pictIn)
        {
            //テンプレ
            Color C1;
            this.h = pictIn.Height;
            this.w = pictIn.Width;
            pictOut = new Bitmap(this.w, this.h);
            byte maxRGB;
            byte minRGB;
            double rgbR, rgbG, rgbB;

            for (int i = 0; i < this.w; i++)
            {
                for (int j = 0; j < this.h; j++)
                {



                    C1 = pictIn.GetPixel(i, j);
                    rgbR = C1.R;
                    rgbG = C1.G;
                    rgbB = C1.B;

                    maxRGB = (byte)Math.Max(rgbR, Math.Max(rgbG, rgbB));
                    minRGB = (byte)Math.Min(rgbR, Math.Min(rgbG, rgbB));


                    if (255 - maxRGB < minRGB)
                    {
                        if (rgbR == maxRGB)
                        {
                            rgbR = 255 * 0.5 + rgbR * 0.5;
                        }
                        else if (rgbB == maxRGB)
                        {
                            rgbB = 255 * 0.5 + rgbB * 0.5;
                        }
                        else
                        {
                            rgbG = 255 * 0.5 + rgbG * 0.5;
                        }
                    }
                    else
                    {
                        if (C1.R == minRGB)
                        {
                            rgbR = rgbR * 0.5;
                        }
                        else if (C1.G == minRGB)
                        {
                            rgbG = rgbG * 0.5;
                        }
                        else
                        {
                            rgbB = rgbB * 0.5;
                        }
                    }

                    pictOut.SetPixel(i, j,
                        Color.FromArgb(
                            (int)rgbR,
                            (int)rgbG,
                            (int)rgbB));
                }
            }
            return pictOut;
        }





        public Bitmap lineFilter(Bitmap pictIn)
        {
            //テンプレ
            Color C1;
            this.h = pictIn.Height;
            this.w = pictIn.Width;
            double r1;
            double r2;
            double[] vecOB = { -1, -1, 1 };
            double[] vecOH = { 0, 0, 0 };
            double[] vecOA = { 0, 0, 0 };
            double[] vecHA = { 0, 0, 0 };
            double[] vecOA2 = { 0, 0, 0 };
            double[] vecCen = { 255, 255, 0 };
            double LenOH, LenOB, LenHA = 0;

            double a = -1.0;
            double b = 2.0;
            LenOB = Math.Sqrt(vecOB[0] * vecOB[0] + vecOB[1] * vecOB[1] + vecOB[2] * vecOB[2]);
            pictOut = new Bitmap(this.w, this.h);



            for (int i = 0; i < this.w; i++)
            {
                for (int j = 0; j < this.h; j++)
                {
                    LenHA = 0;


                    C1 = pictIn.GetPixel(i, j);
                    vecOA[0] = C1.R - vecCen[0];
                    vecOA[1] = C1.G - vecCen[1];
                    vecOA[2] = C1.B - vecCen[2];

                    LenOH = (vecOA[0] * vecOB[0] + vecOA[1] * vecOB[1] + vecOA[2] * vecOB[2]) / LenOB;


                    for (int k = 0; k < 3; k++)
                    {
                        vecOH[k] = LenOH / LenOB * vecOB[k];
                        vecHA[k] = -vecOH[k] + vecOA[k];
                        LenHA += vecHA[k] * vecHA[k];
                    }
                    LenHA = Math.Sqrt(LenHA);
                    r1 = LenHA / 255;
                    r2 = (a * r1 + b);


                    for (int k = 0; k < 3; k++)
                    {
                        //vecOA2[k] = cutNum(0,255,(int)( r2 * vecHA[k]  + vecOH[k]+vecCen[k]));
                        vecOA2[k] = cutNum(0, 255, (int)(r2 * vecHA[k] * 0 + vecOH[k] + vecCen[k]));
                    }

                    pictOut.SetPixel(i, j,
                        Color.FromArgb(
                            (int)vecOA2[0],
                            (int)vecOA2[1],
                            (int)vecOA2[2]));
                }
            }
            return pictOut;
        }


        public Bitmap flatFilter(Bitmap pictIn)
        {
            //テンプレ
            Color C1;
            this.h = pictIn.Height;
            this.w = pictIn.Width;
            int rgbR, rgbG, rgbB;
            pictOut = new Bitmap(this.w, this.h);



            for (int i = 0; i < this.w; i++)
            {
                for (int j = 0; j < this.h; j++)
                {
                    C1 = pictIn.GetPixel(i, j);
                    if (C1.R + C1.G + C1.B > 255)
                    {
                        rgbR = (int)(C1.R * 0.5 + 255 * 0.5);
                        rgbG = (int)(C1.G * 0.5 + 255 * 0.5);
                        rgbB = (int)(C1.B * 0.5 + 255 * 0.5);
                    }
                    else
                    {
                        rgbR = (int)(C1.R * 0.5);
                        rgbG = (int)(C1.G * 0.5);
                        rgbB = (int)(C1.B * 0.5);
                    }
                    pictOut.SetPixel(i, j, Color.FromArgb(rgbR, rgbG, rgbB));
                }
            }
            return pictOut;
        }


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

    }
    public class pict_RGB_And_Deviation
    {
        public double aveR, aveG, aveB;
        public double devR, devG, devB;
        public pict_RGB_And_Deviation(double inAveR, double inAveG, double inAveB, double inDevR, double inDevG, double inDevB)
        {
            aveR = inAveR;
            aveG = inAveG;
            aveB = inAveB;
            devR = inDevR;
            devG = inDevG;
            devB = inDevB;
        }
        public pict_RGB_And_Deviation(Bitmap b1)
        {
            Color C1;
            double countPictSize;
            for (int i = 0; i < b1.Width; i++)
            {
                for (int j = 0; j < b1.Height; j++)
                {
                    C1 = b1.GetPixel(i, j);
                    aveR += (double)C1.R;
                    aveG += (double)C1.G;
                    aveB += (double)C1.B;
                }
            }
            countPictSize = b1.Width * b1.Height;
            aveR /= countPictSize;
            aveG /= countPictSize;
            aveB /= countPictSize;
            for (int i = 0; i < b1.Width; i++)
            {
                for (int j = 0; j < b1.Height; j++)
                {
                    C1 = b1.GetPixel(i, j);
                    devR += ((double)C1.R - aveR) * ((double)C1.R - aveR);
                    devG += ((double)C1.G - aveG) * ((double)C1.G - aveG);
                    devB += ((double)C1.B - aveB) * ((double)C1.B - aveB);
                }
            }
            if (countPictSize > 1)
            {
                countPictSize--;
            }
            else
            {
                countPictSize = 1;
            }

            devR = Math.Sqrt(devR / countPictSize);
            devG = Math.Sqrt(devG / countPictSize);
            devB = Math.Sqrt(devB / countPictSize);
        }
    }
    public class cell
    {
        int sumR = 0;
        int sumG = 0;
        int sumB = 0;
        int count = 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 Color aveColor()
        {
            if (count > 0)
            {
                

                return Color.FromArgb(
                    (int)sumR/count,
                    (int)sumG/count,
                    (int)sumB/count) ;
            }else{
                return (Color.FromArgb(0,0,0) );
            }
        }
    }

}