所以我对此进行了一些思考,然后意识到您正在寻找整张票而不是该票的子集并将其转换为常规矩形。这个问题(至少在理论上)并不是那么困难,而自己编写一些代码来做这件事相对来说是微不足道的。
到目前为止,最困难的部分是初始角点检测。由于您只对整个门票感兴趣,因此门票上的所有内容都没有任何意义。您感兴趣的只是四个角。从你的图片中可以看出,当一张票放在另一张票的上面时,角落并不明显。如果你所有的照片都是一张放在非常黑暗的表面上的票,那么这将再次变得微不足道,但我们的想法是编写一个可以处理模糊情况的应用程序。话虽如此,我建议采用以下方法:
1) 使用图像滤镜使图片的亮区变亮,使图片的暗区变暗。
我忘记了这种滤镜的名称,但基本上你希望在图像的较暗和较亮区域之间有更多的对比。
2) 锐化给定亮度以上的所有区域,高斯模糊给定暗度以下的所有区域
特征查找算法通常依靠图像中的“清晰度”来检测角点和边缘。通过锐化图像的所有较亮区域(考虑到您的票是白色的)并模糊图像的所有较暗区域,您将增加能够通过算法检测到您正在寻找的角落的机会。
3) 使用特征检测来检测四个角
这就是事情会变得棘手的地方。如果您有一堆要拍照的乐透彩票,并且您希望能够通过算法找到一张并无失真地显示它,那么您正在谈论的是当前正在研究的尖端材料。如果这是你想要做的,那么我建议阅读一些 Yanxi Liu 的论文,最著名的是基于平移对称的感知分组与城市场景的应用。您很可能必须从预先制作的门票图片创建一个模板,然后尝试将此模板的确切特征与相机图像中相同特征的扭曲网格相匹配。一旦你有一个高于百分比阈值的匹配,那么你可以尝试找到它的四个角。如果您成功找到它们,那么您可以继续下一步。
另一方面,如果您不想做最前沿的事情,那么您可以只做一些按部就班的特征检测。对于角点检测,我建议使用 Harris & Stephens / Plessey / Shi-Tomasi 角点检测算法。这与 Yanxi 在她的许多论文中使用的算法相同,并且在角点检测方面做得很好。我不确定过滤器是否采用图像的灰度或是否采用当前的色标,但如果是后者,那么在使用角检测算法之前使用 Canny 边缘检测过滤器将是有利的.一旦检测到票的主要角(希望),那么您将需要设计某种智能查找算法(基于照片的视角和内容)来“猜测”哪些角实际上是您关心的四个角.
还值得注意的是,“Mean Shift Belief Propagation”可以帮助您确定检测算法之后最重要的特征。基本上你在一个给定的盒子里取一些特征点,平均它们的所有坐标,然后把盒子放在结果坐标的中心。如果移动后盒子里有新点,那么你再做一次。您继续这样做,直到在框的中心有一个兴趣点。这是对该想法的简要描述,因此我建议您进一步研究,因为我不知道平均细节。
4) 使用双线性插值来确定需要转移到最终图像的颜色。
请务必注意,您不想从已扭曲的图像中获取颜色。在图像上运行所有过滤器和检测算法的目的是找到您感兴趣的特征点。一旦有了这些坐标,您就可以返回使用原始图像来提取颜色。
如果您要问这个问题,那么我假设您知道双线性插值的含义。您会认为扭曲票证的顶部和底部边缘从 0(左角)开始,到 1(右角)结束。您会认为左右边缘从 0(顶角)开始,到 1(底角)结束。您可以将相同的逻辑应用于输出图像的尺寸。在输出图像中逐个像素地查找您需要检索颜色的插值坐标,并使用双线性插值从输入图像中提取颜色。
就是这样! (笑)你要求做的事情很复杂,我祝你好运。据我所知,在没有任何用户输入的情况下创建一个在所有情况下都能完美执行此操作的算法几乎是不可能的。此外,您正在查看乐透彩票这一事实引发了这个项目的道德问题。无论如何,希望这足以让你的大脑开始。以下是一些附加链接:
Canny 边缘检测:http://en.wikipedia.org/wiki/Edge_detection
角点检测:http://en.wikipedia.org/wiki/Corner_detection
刘彦西论文:http://www.cse.psu.edu/~yanxi/
Mean Shift Belief 传播:在我告诉过你的论文中使用
编辑
层级分离代码
int threshold = 128;
float percentChange = .5;
int oldr, oldg, oldb, newr, newg, newb, grayscale;
//Assuming that pixels is a 1D array of pixel objects that make up the image you're currently working with. Syntax is of Processing.org
for (int i=0; i<pixels.length; i++) {
oldr = red(pixels[i]);
oldg = green(pixels[i]);
oldb = blue(pixels[i]);
grayscale = Math.floor((oldr + oldg + oldb) / 3.0);
if (grayScale >= threshold) { //Brightness is above threshold, therefore increase brightness
newr = oldr + (255-oldr)*percentChange;
newg = oldg + (255-oldg)*percentChange;
newb = oldb + (255-oldb)*percentChange;
} else { //Brightness is below threshold, therefore increase darkness
newr = oldr - oldr*percentChange;
newg = oldg - oldg*percentChange;
newb = oldb - oldb*percentChange;
}
pixels[i] = color(newr,newg,newb);
}