zoukankan      html  css  js  c++  java
  • 码农干货系列【4】图像识别之矩形区域搜索

    简介

    定位某个图片的矩形区域是非常有用的,这个可以通过手动的选择某个区域来实现定位,图片相关的软件都提供了这个功能;也可以像本篇一个通过程序来实现智能定位。前者会有误差,效率低下;后者选区精度高,效率高。

    应用场景

    1.精灵编辑器或者css sprites辅助工具(当我们需要逆着TexturePacker行事的时候),如下图所示:

    image

    2.手写识别输入

    image image

    因为我们不能保证用户输入的区域,所以必须定位到用户输入的区域,再去识别用户的输入的内容。

    3.魔法画板程序

    比如马良神笔,要对用户绘制的火柴人进行一些上下左右移动、扭曲等效果:

    image

    矩形区域识别

    废话一万句,不如一张图。看下面这张图:

    image

    这就是识别的关键。任意取图像上的一点,然后通过这点开始扩张。一般情况下,该点取的是软件使用者鼠标点击的那一点。如图是移动中的四个点:

    image

    可以看到,移动后的四个点可以确定一个矩形区域。哪条边下的所有像素为透明(即0,0,0,0),则该点不移动,等待其他点移动完成。当所有边下面的像素都为透明,则得到了我们想要的区域。我们根据移动的距离可以很方便的找到四个顶点:

    image

    所以一个递归就可以帮我们实现(js Canvas版):


    var increasePixel = 1, leftIncreasePixel = 2, rightIncreasePixel = 2, upIncreasePixel = 2, downIncreasePixel = 2;
    function searchTransparentRectByTargetPoint(p) {

    var p1 = { x: p.x - leftIncreasePixel, y: p.y - upIncreasePixel };
    var p2 = { x: p.x + rightIncreasePixel, y: p.y - upIncreasePixel };
    var p3 = { x: p.x + rightIncreasePixel, y: p.y + downIncreasePixel };
    var p4 = { x: p.x - leftIncreasePixel, y: p.y + downIncreasePixel };

    var breakTag = true;
    if (!isXLineTransparent(p1, p2)) {
    upIncreasePixel += increasePixel;
    breakTag = false;
    }
    if (!isYLineTransparent(p2, p3)) {
    breakTag = false;
    rightIncreasePixel += increasePixel;
    }
    if (!isXLineTransparent(p4, p3)) {
    breakTag = false;
    downIncreasePixel += increasePixel;
    }
    if (!isYLineTransparent(p1, p4)) {
    breakTag = false;
    leftIncreasePixel += increasePixel;
    }

    if (breakTag) {
    return [p1.x, p1.y, p3.x - p1.x, p3.y - p1.y];
    } else {
    return searchTransparentRectByCenterPoint(p);
    }
    }

    其中isXLineTransparent和isYLineTransparent是获取该线段下面是否全透明。


    function isXLineTransparent(p1, p2) {
    var _y = p2.y;
    for (var i = p1.x; i < p2.x + 1; i++) {
    var startIndex = this.getImageDataStartIndexByPosition({ x: i, y: _y });
    var totalPixel = this.imageData.data[startIndex] + this.imageData.data[startIndex + 1] + this.imageData.data[startIndex + 2] + this.imageData.data[startIndex + 3];
    if (totalPixel !== 0) {
    return false;
    }
    }
    return true;
    }

    function isYLineTransparent(p1, p2) {
    var _x = p2.x;
    for (var i = p1.y; i < p2.y + 1; i++) {
    var startIndex = this.getImageDataStartIndexByPosition({ x: _x, y: i });
    var totalPixel = this.imageData.data[startIndex] + this.imageData.data[startIndex + 1] + this.imageData.data[startIndex + 2] + this.imageData.data[startIndex + 3];
    if (totalPixel !== 0) {
    return false;
    }
    }
    return true;
    }

    多矩形区域识别策略

    多矩形区域识别是没有扩张点,需要从用户输入中随机产生一个目标点,然后使用两层递归(上面的代码之外再嵌套一层)实现所有矩形区域的遍历。

    image

    思路有了,是不是有想法把上面的手写输入改成支持多个文字?这个对于聪明的你,明显不是问题。

    在线演示

    传送门:http://www.spritecow.com/

  • 相关阅读:
    LeetCode
    数据流中的中位数
    二叉搜索树的第k个结点
    对称的二叉树
    按之字形顺序打印二叉树
    把二叉树打印成多行
    二叉树的下一个结点
    链表中环的入口结点
    删除链表中重复的结点
    不用加减乘除做加法
  • 原文地址:https://www.cnblogs.com/iamzhanglei/p/2604313.html
Copyright © 2011-2022 走看看