今天又试验了:邻误差<=4进行聚类。以前觉得比较相邻两个像素的误差就可以聚类,实测输出结果却是那么差劲。原来相邻像素基本都是相似的,对渐变过度的边缘难以消化。37万像素聚类用了0.3秒,统计并生成9张面积最大的聚类则用了约0.2秒
将来有空再改善一下。假如不比相邻像素,比较相近的一小片区域效果肯定更好吧。
//由于渐变相邻导致的误判,需要增加判断距离,增加聚类判断条件
bitmapOp = objImage.getPeekImage();
int 容差值; //两个像素之间误差值, // msgbox("??");
if (text_信息框.Text == "") 容差值 = 12; else 容差值 = int.Parse(text_信息框.Text);
mytimer.Start();
Stack
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
IDictionary
//统计每个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();