- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在开发可以在 Jade 米裁剪中运行并由罗盘传感器引导的机器人,但我想将相机用作机器人的眼睛,并使用图像处理来检测运动的误差角度。
这是图像示例。
我使用以下步骤
第 1 步:我目前使用的技术是将颜色值转换为从 this code 修改而来的 HSV
第 2 步:因此它将检测选定的颜色,即棕色或污垢颜色,然后我收集两个阵列中每个图像行的最左边和右边的棕色或选定颜色(一个红点)。
问题是如何过滤掉 Jade 米叶之间或不在 Jade 米路径中的其他区域的棕色像素?我应该研究或应用哪种算法或方法来解决这个问题?
EDIT1:使用 Spektre 的答案,看起来更好
这是我用JAVA+Boofcv应用后的结果
More Information
最佳答案
对于您的源图像
我会:
制作棕色面具
只是阈值 H,S
并忽略 V
,你已经有了这个。我使用整数 255
而不是颜色(蓝色)用于后面的计算。
模糊蒙版
这将删除错误选择的部分的小簇。在此之后,您应该再次对掩码进行阈值处理,因为掩码值会比 255
小一点。除非你有完全选择的区域。面积越大,值越大(接近 255
)。我以>=150
为阈值
水平线扫描蒙版
为每条线找到所有选定像素的重心
再次进行模糊和阈值处理后,使用过的蒙版位于 Aqua 中。所以计算平均点 x
每行中所有屏蔽像素的坐标。此点用白色标记。
通过所有重心的回归线
我用我的approximation search为此,您可以使用任何您想要的回归。回归线标有红色
我使用线方程 x=x0+y*dx
其中 y=<0,pic1.ys>
.并按时间间隔搜索解决方案:
x0=<-pic1.xs,+2*pic1.xs>
dx=<-10,+10>
在哪里pic1.xs,pic1.ys
是图像分辨率。因此,正如您所看到的,我没有涵盖所有角度范围,但我认为这无论如何都不适用于那些边缘情况(接近水平方向)。对于这种情况,您应该在垂直线上执行此操作并使用 x=y0+x*dy
相反。
这里是 C++ 来源,我是用它来做的:
picture pic0,pic1;
// pic0 - source img
// pic1 - output img
int x,y,h,s,v,px,pn,*p;
color c;
// copy source image to output
pic1=pic0;
pic1.save("cornbot0.png");
// create brown stuff mask
for (y=0;y<pic1.ys;y++) // scan all H lines
for (x=0;x<pic1.xs;x++) // scan actual H line
{
c=pic1.p[y][x]; // get pixel color
rgb2hsv(c); // in HSV
h=WORD(c.db[picture::_h]);
s=WORD(c.db[picture::_s]);
v=WORD(c.db[picture::_v]);
// Treshold brownish stuff
if ((abs(h- 20)<10)&&(abs(s-200)<50)) c.dd=255; else c.dd=0;
pic1.p[y][x]=c;
}
pic1.save("cornbot1.png");
pic1.smooth(10); // blur a bit to remove small clusters as marked
pic1.save("cornbot2.png");
// compute centers of gravity
p=new int[pic1.ys]; // make space for points
for (y=0;y<pic1.ys;y++) // scan all H lines
{
px=0; pn=0; // init center of gravity (avg point) variables
for (x=0;x<pic1.xs;x++) // scan actual H line
if (pic1.p[y][x].dd>=150) // use marked points only
{
px+=x; pn++; // add it to avg point
pic1.p[y][x].dd=0x00004080; // mark used points (after smooth) with Aqua
}
if (pn) // finish avg point computation
{
px/=pn;
pic1.p[y][px].dd=0x00FFFFFF;// mark it by White
p[y]=px; // store result for line regression
} else p[y]=-1; // uncomputed value
}
// regress line
approx x0,dx;
double ee;
for (x0.init(-pic1.xs,pic1.xs<<1,100,3,&ee); !x0.done; x0.step()) // search x0
for (dx.init(-10.0 ,+10.0 ,1.0,3,&ee); !dx.done; dx.step()) // search dx
for (ee=0.0,y=0;y<pic1.ys;y++) // compute actua solution distance to dataset
if (p[y]!=-1) // ignore uncomputed values (no brown stuff)
ee+=fabs(double(p[y])-x0.a-(double(y)*dx.a));
// render regressed line with Red
for (y=0;y<pic1.ys;y++)
{
x=double(x0.aa+(double(y)*dx.aa));
if ((x>=0)&&(x<pic1.xs))
pic1.p[y][x].dd=0x00FF0000;
}
pic1.save("cornbot2.png");
delete[] p;
我用自己的picture
图像类,所以一些成员是:
xs,ys
以像素为单位的图像大小p[y][x].dd
像素位于 (x,y)
定位为32位整数类型p[y][x].dw[2]
像素位于 (x,y)
2D 字段的位置为 2x16 位整数类型p[y][x].db[4]
像素位于 (x,y)
定位为4x8位整数类型,方便 channel 访问clear(color)
- 清除整个图像resize(xs,ys)
- 将图像调整为新的分辨率bmp
- VCL 封装了 GDI 位图与 Canvas 访问smooth(n)
- 快速模糊图像 n
次您可以通过基于区域和位置的分割(移除小簇)进一步改进这一点。您也可以忽略邻居之间的平均点中太大的峰值。您还可以检测天空并忽略存在天空的整个区域。
[edit1] 平滑
这是我平滑的样子:
void picture::smooth(int n)
{
color *q0,*q1;
int x,y,i,c0[4],c1[4],c2[4];
bool _signed;
if ((xs<2)||(ys<2)) return;
for (;n>0;n--)
{
#define loop_beg for (y=0;y<ys-1;y++){ q0=p[y]; q1=p[y+1]; for (x=0;x<xs-1;x++) { dec_color(c0,q0[x],pf); dec_color(c1,q0[x+1],pf); dec_color(c2,q1[x],pf);
#define loop_end enc_color(c0,q0[x ],pf); }}
if (pf==_pf_rgba) loop_beg for (i=0;i<4;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u8(c0[i]); } loop_end
if (pf==_pf_s ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])/ 4; clamp_s32(c0[0]); } loop_end
if (pf==_pf_u ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])>>2; clamp_u32(c0[0]); } loop_end
if (pf==_pf_ss ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])/ 4; clamp_s16(c0[i]); } loop_end
if (pf==_pf_uu ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u16(c0[i]); } loop_end
#undef loop_beg
#define loop_beg for (y=ys-1;y>0;y--){ q0=p[y]; q1=p[y-1]; for (x=xs-1;x>0;x--) { dec_color(c0,q0[x],pf); dec_color(c1,q0[x-1],pf); dec_color(c2,q1[x],pf);
if (pf==_pf_rgba) loop_beg for (i=0;i<4;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u8(c0[i]); } loop_end
if (pf==_pf_s ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])/ 4; clamp_s32(c0[0]); } loop_end
if (pf==_pf_u ) loop_beg { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])>>2; clamp_u32(c0[0]); } loop_end
if (pf==_pf_ss ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])/ 4; clamp_s16(c0[i]); } loop_end
if (pf==_pf_uu ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u16(c0[i]); } loop_end
#undef loop_beg
#undef loop_end
}
}
它只是对3个像素进行加权平均
(x,y)=(2*(x,y)+(x-1,y)+(x,y-1))/4
然后做同样的事情
(x,y)=(2*(x,y)+(x+1,y)+(x,y+1))/4
避免图像偏移。然后整个事情循环了n
次,仅此而已。您可以忽略 clamp 和 pixel-format 选项,在这种情况下它是 pf==_pf_rgba
但无论如何它只使用单 channel ... dec_color,enc_color
只需将颜色 channel 解包、打包到变量数组中或从变量数组中打包,以避免 8 位 channel 上的截断和溢出问题,并更好地格式化/简化代码(对于不同的像素格式支持)
顺便说一句,平滑基础与卷积相同
0.00 0.25 0.00
0.25 0.50 0.00
0.00 0.00 0.00
和
0.00 0.00 0.00
0.00 0.50 0.25
0.00 0.25 0.00
关于java - 如何从图像中检测机器人方向?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37155580/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!