>将输入图像和调整大小的图像调整为标准尺寸
因为我必须将它与模板进行比较.
>使用阈值转换为二进制.
>检测到连接的组件并显示最大的组件.
因为它是整个手.如下所示:
>将图像放置在相同的坐标处以检查手指的放置以与模板图像进行比较
但是他们的定位是不同的紫色是模板图像
这些情况无法预测它们是否是发际线断裂,因为它们在图像中检测到许多小线.
他们还有其他任何方法吗?如果有的话,请告诉我.
原始未处理的图像:
解决方法
>准备图像
切换到灰度,消除噪音(通过一些模糊),增强动态范围等.
>通过x,y轴导出图像并创建渐变2D场
所以重新着色图像并创建2D矢量场.每个像素都有RGB,因此对一个轴使用R而对另一个使用B.我是这样做的:
Blue(x,y)=abs(Intensity(x,y)-Intensity(x-1,y)) Red (x,y)-Intensity(x,y-1))
因此,选择每个像素并比较蓝色(x,y)红色(x,y)< treshold,如果真的重新着色到未知的其他重新着色到边缘颜色.对于您的样本图像,我使用阈值24之后平滑结果以填充模糊颜色的小间隙.子结果如下所示:
绿色的东西是我未知的颜色,白色是边缘.正如你所看到的,我模糊了很多(懒得实现连接的组件).
>检测背景
所以现在要区分背景和里面的骨头我使用特殊的填充方法(但是简单的填充填充会做)我开发的DIP东西,并发现非常有用多次超过以前的期望.
void growfill(DWORD c0,DWORD c1,DWORD c2); // grow/flood fill c0 neigbouring c1 with c2
它只是检查图像中的所有像素,如果在c1附近找到颜色c0,则将其重新循环到c2并循环,直到没有重新着色.由于不需要递归或堆栈/堆/列表,因此更大的分辨率通常比泛洪更快.此外,它可用于许多很酷的效果,如稀释/加厚等,只需简单的几个电话.
好的回到我选择3种基色的主题:
//RRGGBB const DWORD col_unkNown =0x00408020; // yet undetermined pixels const DWORD col_background=0x00000000; const DWORD col_edge =0x00FFFFFF;
现在背景是边缘肯定所以我用col_background绘制矩形图像和增长填充col_background附近的所有col_unkNown像素与col_background基本上洪水填充图像从外到内.
在此之后,我将所有不是3种定义颜色中的任何颜色的像素重新着色到它们最接近的匹配.这将消除模糊,因为它不再需要.子结果如下所示:
>细分/标签
现在只扫描整个图像,如果发现任何col_unkNown,则使用对象不同的颜色/索引填充它.更改实际对象的不同颜色/索引(增量)并继续直到图像结束.请注意您拥有的颜色,以避免使用3种预定颜色,否则您将合并您不想要的区域.
您有每个对象区域的像素掩码,因此您可以计算像素(区域)并删除忽略太小的区域.计算每个对象的平均像素位置(中心),并使用它来检测它实际上是哪个骨骼.计算区域的同质性…重新缩放到模板骨骼……等等……
这里有一些C代码我这样做了
color c,d; int x,y,i,i0,i1; int tr0=Form1->sb_treshold0->Position; // =24 treshold from scrollbar //RRGGBB const DWORD col_unkNown =0x00408020; // yet undetermined pixels const DWORD col_background=0x00000000; const DWORD col_edge =0x00FFFFFF; // [prepare image] pic1=pic0; // copy input image pic0 to output pic1 pic1.pixel_format(_pf_u); // convert to grayscale intensity <0,765> pic1.enhance_range(); // recompute colors so they cover full dynamic range pic1.smooth(1); // blur a bit to remove noise // extract edges pic1.deriveaxy(); // compute derivations (change in intensity in x and y axis as 2D gradient vector) pic1.save("out0.png"); pic1.pf=_pf_rgba; // from Now on the recolored image will be RGBA (no need for conversion) for (y=0;y<pic1.ys;y++) // treshold recolor for (x=0;x<pic1.xs;x++) { c=pic1.p[y][x]; i=c.dw[picture::_x]+c.dw[picture::_y]; // i=|dcolor/dx| + |dcolor/dy| if (i<tr0) c.dd=col_unkNown; else c.dd=col_edge; // treshold test&recolor pic1.p[y][x]=c; } pic1.smooth(5); // blur a bit to fill the small gaps pic1.save("out1.png"); // [background] // render backround color rectangle around image pic1.bmp->Canvas->Pen->Color=rgb2bgr(col_background); pic1.bmp->Canvas->Brush->Style=bsClear; pic1.bmp->Canvas->Rectangle(0,pic1.xs,pic1.ys); pic1.bmp->Canvas->Brush->Style=bsSolid; // growth fill all col_unknonw pixels near col_background pixels with col_background similar to floodfill but without recursion and more usable. pic1.growfill(col_unkNown,col_background,col_background); // recolor blured colors back to their closest match for (y=0;y<pic1.ys;y++) for (x=0;x<pic1.xs;x++) { c=pic1.p[y][x]; d.dd=col_edge ; i=abs(c.db[0]-d.db[0])+abs(c.db[1]-d.db[1])+abs(c.db[2]-d.db[2]); i0=i; i1=col_edge; d.dd=col_unkNown ; i=abs(c.db[0]-d.db[0])+abs(c.db[1]-d.db[1])+abs(c.db[2]-d.db[2]); if (i0>i) { i0=i; i1=d.dd; } d.dd=col_background; i=abs(c.db[0]-d.db[0])+abs(c.db[1]-d.db[1])+abs(c.db[2]-d.db[2]); if (i0>i) { i0=i; i1=d.dd; } pic1.p[y][x].dd=i1; } pic1.save("out2.png"); // [segmentation/labeling] i=0x00202020; // labeling color/idx for (y=0;y<pic1.ys;y++) for (x=0;x<pic1.xs;x++) if (pic1.p[y][x].dd==col_unkNown) { pic1.p[y][x].dd=i; pic1.growfill(col_unkNown,i); i+=0x00050340; } pic1.save("out3.png");
> xs,ys图像大小,以像素为单位
> p [y] [x] .dd是(x,y)位置的像素,为32位整数类型
> p [y] [x] .dw [2]是(x,为2D场的2×16位整数类型
> p [y] [x] .db [4]是(x,为4×8位整数类型,便于通道访问
>清晰(彩色) – 清除整个图像
> resize(xs,ys) – 将图像调整为新分辨率
> bmp – VCL封装了带Canvas访问的GDI Bitmap
> smooth(n) – 快速模糊图像n次
> growfill(DWORD c0,DWORD c2) – 使用c2生长/填充c0 neigbouring c1
[Edit1]基于扫描线的骨骼检测
与链接查找范围QA一样,您必须投射扫描线并搜索识别骨骼的不同特征.我会从图像的局部推导开始(在x轴上)像这样::
左边是x的颜色强度推导(灰色表示零)和右边的原始图像.侧图是作为x和y的函数的推导图,用于实际鼠标位置的行和行.如您所见,每个骨骼在推导中具有可以检测到的独特形状.我使用了一个非常简单的探测器:
>对于已处理的图像行,请执行x的部分派生
>找到所有的山峰(圆圈)
>删除太小的峰并将相同的符号峰合并在一起
>通过4个随后的峰检测骨骼:
>大阴性
>小积极
>小负面
>大积极
对于每个找到的骨骼边缘,我在原始图像中渲染红色和蓝色像素(代替大峰值)以在视觉上检查正确性.您也可以在y轴上以相同的方式执行此操作并合并结果.为了改善这一点,您应该使用更好的检测,例如通过使用相关性…
而不是边缘渲染您可以轻松创建骨骼的蒙版,然后将其分割为单独的骨骼和句柄,如上文所示.您还可以使用形态学操作来填补任何空白.
我能想到的最后一件事是为骨骼的关节侧添加一些检测(形状有所不同).它需要大量的实验,但至少你知道要走哪条路.