简单聚类实验

今天又试验了:邻误差<=4进行聚类。以前觉得比较相邻两个像素的误差就可以聚类,实测输出结果却是那么差劲。原来相邻像素基本都是相似的,对渐变过度的边缘难以消化。37万像素聚类用了0.3秒,统计并生成9张面积最大的聚类则用了约0.2秒

将来有空再改善一下。假如不比相邻像素,比较相近的一小片区域效果肯定更好吧。

//由于渐变相邻导致的误判,需要增加判断距离,增加聚类判断条件
            bitmapOp = objImage.getPeekImage();
            int 容差值;  //两个像素之间误差值,  // msgbox("??");
            if (text_信息框.Text == "") 容差值 = 12; else 容差值 = int.Parse(text_信息框.Text);
            mytimer.Start();
            Stack<int> StackID = new Stack<int>();  //堆栈集合的Point类
            TimerMark.Start();
            unsafe
            {
                int bmpWidth = bitmapOp.Width;
                int bmpHeight = bitmapOp.Height;              //rd("\r" + Width.ToString() + Height.ToString());
                int count_id = bmpWidth * bmpHeight;
                int[,] arr = new int[bmpWidth, bmpHeight];
                 
                Rectangle rect = new Rectangle(0, 0, bmpWidth, bmpHeight);
                System.Drawing.Imaging.BitmapData srcData = bitmapOp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//curBitmap.PixelFormat
                rgbClassRef[,] piex = new rgbClassRef[bmpWidth, bmpHeight];//多1行1列 
                byte* ptr = (byte*)(srcData.Scan0);
                int iOffset = srcData.Stride - srcData.Width * 3;  //我喜欢这样的定义,标准 
                
                int index =0;
                for (int y = 0; y < bmpHeight; y++)
                {
                    for (int x = 0; x < bmpWidth; x++)
                    {
                        rgbClassRef rgb = new rgbClassRef();//实例化 
                        rgb.SetRGB(ref ptr[2], ref ptr[1], ref  ptr[0]);
                        arr[x, y] = index++;
                        rgb.setid(ref arr[x, y]);     //每个rgb对象ID指向一个数组序列的值  *subid=arr(x)    
                        piex[x, y]  = rgb ; 
                        ptr += 3;                           //Format24bppRgb格式每个像素占3字节 // 移动指针,取下一个点:右侧像素  
                    }//for1
                     ptr += iOffset;      //每行读取到最后“有用”数据时,跳过未使用空间XX
                }//for2 
                  rd("\r" + TimerMark.GetSeconds().ToString() + "完成" + index + "个RGB对象创建\r");
                
                //piexOut[0, 2].setid(ref 物件ID[0, 0]);  //重新绑定
                //物件ID[0, 0] = 5;

                

                TimerMark.Start();
 

                for (int y = 0; y < bmpHeight - 1; y++)
                {
                    for (int x = 0; x < bmpWidth - 1; x++)
                    {
                        if (两点相似度(piex[x, y], piex[x + 1, y]) <= 容差值) //访问过标记)//左与右同色,右边已经访问过 if (piex[x, y].Color == piex[x + 1, y].Color)//左右相同色彩
                        {
                            if (piex[x, y].ID < piex[x + 1, y].ID)
                            {
                                piex[x + 1, y].ID = piex[x, y].ID; piex[x + 1, y].setid(ref  *piex[x, y].sid); //取小ID  
                            }
                            else
                            { piex[x, y].ID = piex[x + 1, y].ID; piex[x, y].setid(ref *piex[x + 1, y].sid); }   //取小ID 

                        }
                       
                        if (两点相似度(piex[x, y], piex[x, y + 1]) <= 容差值)//上与下同色
                        {
                            piex[x, y + 1].setid(ref *piex[x, y].sid);

                            //piex[x, y + 1].visit = true; //已访问标记
                        }

                    }//for1 w
                } //for2  h

                TimerMark.Start();

                for (int y = bmpHeight - 1; y > 0; y--)
                {
                    for (int x = bmpWidth - 1; x > 0; x--)
                    {
                        if (两点相似度(piex[x, y], piex[x - 1, y]) <= 容差值) //访问过标记)//左与右同色,右边已经访问过
                        {
                            if (piex[x, y].ID < piex[x - 1, y].ID)
                            {
                                piex[x - 1, y].ID = piex[x, y].ID; piex[x - 1, y].setid(ref *piex[x, y].sid); //取小ID  
                            }
                            else
                            { piex[x, y].ID = piex[x - 1, y].ID; piex[x, y].setid(ref *piex[x - 1, y].sid); }   //取小ID 

                        }

                        if (两点相似度(piex[x, y], piex[x, y - 1]) <= 容差值)//上与下同色
                        {
                            if (piex[x, y - 1].ID < piex[x, y].ID)
                            {
                                piex[x, y].setid(ref *piex[x, y - 1].sid);
                            }
                            else
                            {
                                piex[x, y - 1].setid(ref *piex[x, y].sid);
                            }
                        }
                    }//FOR1
                }//FOR2


                rd("\r" + TimerMark.GetSeconds().ToString() + "完成右下角比较\r");


                TimerMark.Start();
                IDictionary<int, int> Dic = new Dictionary<int, int>();//创建每幅图对应的 字典对象 ,保存图像的属性值 
                IDictionary<int, int> DicSort = new Dictionary<int, int>();//创建每幅图对应的 字典对象 ,保存图像的属性值 

                //统计每个ID 出现的次数 
                //foreach (rgbClassRef  rgb in piexOut) //遍历ID号,比两个FOR慢                    {
                //{
                //    int TmpID = rgb.ID;
                //    if (Dic.ContainsKey(TmpID)) { Dic[TmpID] += 1; } else { Dic.Add(TmpID, 1); } //统计每个ID 出现的次数 

                //}
                //统计每个ID 出现的次数 
                for (int y = 0; y < bmpHeight; y++)
                {
                    for (int x = 0; x < bmpWidth; x++)
                    {
                        int TmpID = piex[x, y].ID;
                        if (Dic.ContainsKey(TmpID)) { Dic[TmpID] += 1; } else { Dic.Add(TmpID, 1); } //统计每个ID 出现的次数 
                        //if (piexOut[x, y].ID == arr[0])
                        //{
                        //    piexOut[x, y].Color = Color.FromArgb(255, 0, 0);
                        //}
                    }
                }
                rd("\r" + TimerMark.GetSeconds().ToString() + "完成排序比较\r");
                TimerMark.Start();
                //统计ID重复最大的像素,9个图片ID就退出 
                while (true)
                {
                    if (DicSort.Count > 9 || Dic.Count == 0) break;//找到9个图片就退出
                    int maxkey = 0, maxC = 0;
                    foreach (int key in Dic.Keys) //遍历ID号
                    {

                        if (maxC < Dic[key]) { maxC = Dic[key]; maxkey = key; }

                    }
                    Dic.Remove(maxkey);
                    DicSort.Add(maxkey, maxC);
                }
                rd(TimerMark.GetSeconds().ToString() + ",9次循环字典每个ID 出现的次数统计工作" + Dic.Count.ToString() + "\r");

                TimerMark.Start();
                int imgcount = 0;
                foreach (int key in DicSort.Keys) //遍历ID号
                {
                    // richTextBox1.AppendText("\r  物件ID=" + key.ToString() + ",像素总数=" + DicSort[key]);
                    Bitmap wjsb2 = new Bitmap(bmpWidth, bmpHeight);
                    BitmapData bmpData2 = wjsb2.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//curBitmap.PixelFormat
                    ptr = (byte*)(bmpData2.Scan0);  //数据头指针  
                    for (int y = 0; y < bmpHeight; y++)
                    {
                        for (int x = 0; x < bmpWidth; x++)
                        {
                            if (piex[x, y].ID == key)
                            {
                                //wjsb2.SetPixel(x, y, piex[x, y].Color);//原来的色彩
                                ptr[2] = piex[x, y].Color.R; ptr[1] = piex[x, y].g; ptr[0] = piex[x, y].b;

                            }
                            else
                            {
                                ptr[2] = 255; ptr[1] = 255; ptr[0] = 0;
                            }

                            ptr += 3;
                        }
                        ptr += iOffset;       //每行读取到最后“有用”数据时,跳过未使用空间XX
                    }
                    wjsb2.UnlockBits(bmpData2);

                    if (imgcount == 0) { lbid1.Text = "ID=" + key.ToString(); curBoxBmp1 = new Bitmap(wjsb2); pBox1.Image = new Bitmap(wjsb2, pBox1.Size); }//
                    else if (imgcount == 1) { lbid2.Text = "ID=" + key.ToString(); curBoxBmp2 = new Bitmap(wjsb2); pBox2.Image = new Bitmap(wjsb2, pBox2.Size); }
                    else if (imgcount == 2) { lbid3.Text = "ID=" + key.ToString(); curBoxBmp3 = new Bitmap(wjsb2); pBox3.Image = new Bitmap(wjsb2, pBox3.Size); }
                    else if (imgcount == 3) { lbid4.Text = "ID=" + key.ToString(); curBoxBmp4 = new Bitmap(wjsb2); pBox4.Image = new Bitmap(wjsb2, pBox4.Size); }
                    else if (imgcount == 4) { lbid5.Text = "ID=" + key.ToString(); curBoxBmp5 = new Bitmap(wjsb2); pBox5.Image = new Bitmap(wjsb2, pBox5.Size); }
                    else if (imgcount == 5) { lbid6.Text = "ID=" + key.ToString(); curBoxBmp6 = new Bitmap(wjsb2); pBox6.Image = new Bitmap(wjsb2, pBox6.Size); }
                    else if (imgcount == 6) { lbid7.Text = "ID=" + key.ToString(); curBoxBmp7 = new Bitmap(wjsb2); pBox7.Image = new Bitmap(wjsb2, pBox7.Size); }
                    else if (imgcount == 7) { lbid8.Text = "ID=" + key.ToString(); curBoxBmp8 = new Bitmap(wjsb2); pBox8.Image = new Bitmap(wjsb2, pBox8.Size); }
                    else if (imgcount == 8) { lbid9.Text = "ID=" + key.ToString(); curBoxBmp9 = new Bitmap(wjsb2); pBox9.Image = new Bitmap(wjsb2, pBox9.Size); }
                    imgcount++;
                }//每个图片输出

               rd("\r" + TimerMark.GetSeconds().ToString() + "秒图片输出工作\r");


     
              

                // rd(TimerMark.GetSeconds().ToString() + "图片输出工作\r");                 //   msgbox(piex[x, y].ID);                 // piex[x, y].Color = Color.FromArgb(0,0, 0);                  // msgbox(rgb1.r + "," + rgb1.g + "," + rgb1.b); msgbox(rgb2.r + "," + rgb2.g + "," + rgb2.b);                 bitmapOp.UnlockBits(srcData);                             }//unsafe               pboxA.Image = bitmapOp;// FitPictureBox(bitmapOp, pboxA);             text_Timer.Text = mytimer.GetSeconds().ToString(); //TimerMark.GetSeconds().ToString();