【问题标题】:how can I detect all the text that inside a block with Google Vision Api如何使用 Google Vision Api 检测块内的所有文本
【发布时间】:2020-01-09 01:54:42
【问题描述】:

我正在尝试使用 google vision api 从图像中提取文本,它可以工作。但我只想检测图像的一部分以获得某些文本。

这是我使用的图像

我只想提取从maybank2u.comFrom Account: 的所有文本 我知道有一些教程可以通过使用块来完成这个技巧,但这些教程是不同的编程语言。

我的代码:

<div class="row">
    <div class="col-12">
        <ol>
            <?php foreach ($text as $key => $texts): ?> 
                <li><h6> <?php echo ucfirst($texts->info()['description']) ?></h6><<br><br> 
                </li>
            <?php endforeach ?>
        </ol>
    </div>
</div>

此代码将从图像中获取所有文本

输出:

【问题讨论】:

    标签: php google-api ocr google-vision text-recognition


    【解决方案1】:

    下面的代码对我有用。我有一个 php 文件 test.php 和一个图像文件 /images/UUIPXl.png。

    为了获取每一行文本,我从 Google Vision 迭代文本注释,并创建一个行项目数组。其中每一个都有一个 x 位置和一个文本值。

    然后我按 x 位置对每一行进行排序并连接以创建一行文本。

    最后,一旦我们得到最终所需的文本行,我们就会停下来。

    我得到这样的结果:

    • maybank2u.com
    • 打开账单支付
    • 状态:成功
    • 参考号:2950211545
    • 成交日期:2016-02-01 13:09:17
    • 金额:RM100.00
    • 来自帐户 564155051577 WCA

    php代码:

    <?php 
    
        require 'vendor/autoload.php';
        use Google\Cloud\Vision\VisionClient;
    
        $config = ["keyFile" => json_decode(file_get_contents("./APIKey.json"), true) ];
        $vision = new VisionClient($config);
    
        $image = $vision->image(
            fopen('./images/UUIPXl.png', 'r'),
            ['TEXT_DETECTION']
        );
    
        $textAnnotations = $vision->annotate($image)->text();
        $rows = [];
    
        // Function used to sort our lines.
        function sortProc($a, $b)
        {
            if ($a["x"] === $b["x"]) {
                return 0;
            }
            return ($a["x"] < $b["x"]) ? -1 : 1;
        }
    
        // Remove first row (complete text).
        array_shift($textAnnotations);
    
        // We should calculate this, use a reasonable value to begin with.
        $lineHeight = 8;
    
        foreach ($textAnnotations as $text) {
            $key = round(((double)($text->info()["boundingPoly"]["vertices"][0]["y"]))/$lineHeight);
            $x = (int)$text->info()["boundingPoly"]["vertices"][0]["x"];
            $value = ["x" => $x, "text" => $text->description()];
            if (!isset($rows[$key])) {
                $rows[$key] = [];
            }
            $rows[$key][] = $value;
        }
    
        $text = [];
        foreach ($rows as $key => $value) {
            // Sort by x value.
            usort($value, "sortProc");
    
            // Concatenate each line
            $result = array_reduce($value, function($acc, $elem) {
                $acc .= " " . $elem["text"];
                return $acc;
            }, "");
    
            $text[] = $result;
    
            // Stop when we get here!
            if (preg_match("/from account/i", $result)) {
                break;
            }
        }
    
    ?>
    
    <div class="row" style="padding: 20px;">
        <div class="col-12">
            <ul>
                <?php foreach ($text as $row): ?> 
                    <li><h3> <?php echo ucfirst($row) ?></h3></li>
                <?php endforeach ?>
            </ul>
        </div>
    </div>
    

    【讨论】:

    • 感谢您的尝试,请问if (preg_match("/from account/i", $result)) 这一行中的i 是什么意思?
    • 我试过你的代码,它可以工作,但我可以在Reference number: 2950211545From Account 564155051577 WCA 行中得到:
    • 哦,尾随的 /i 用于不区分大小写的匹配。我认为在 PHP 中,这通常像 #from account#i 一样完成。
    • Reference number 行应该包含“:”字符,“From Account”行似乎有点问题,我认为“:”字符根本无法识别。跨度>
    • 图片的分辨率相对较低(541 x 466),这可以解释文本不是100%准确的事实。
    【解决方案2】:

    如果您只想限制输出及其每次应该停止执行的相同字符串,请执行以下操作:

    <div class="row">
        <div class="col-12">
            <ol>
                <?php foreach ($text as $key => $texts): ?> 
                    <?php if (strpos($texts->info()['description'], 'From Account') !== false) break; ?>
                    <li><h6> <?php echo ucfirst($texts->info()['description']) ?></h6><<br><br> 
                    </li>
                <?php endforeach ?>
            </ol>
        </div>
    </div>
    

    说明:
    如果$texts-&gt;info()['description'] 包含文本From Account,它将通过break 结束foreach 循环的执行。如果您需要检查多个关键字read this

    另一种解决方案是在将图像发送到 API 之前使用 imagecrop() 裁剪图像。但为此,您需要确保它永远不会改变文本的大小/位置。

    附:你确定每个人都应该在你的截图中看到这些私人数据吗?

    更新1
    如你所问。这将是相同的代码,但使用 alternative syntax for control structures:

    <div class="row">
        <div class="col-12">
            <ol>
                <?php foreach ($text as $key => $texts): ?> 
                    <?php if (strpos($texts->info()['description'], 'From Account') !== false): ?>
                    <?php break; ?>
                    <?php endif; ?>
                    <li><h6> <?php echo ucfirst($texts->info()['description']) ?></h6><<br><br> 
                    </li>
                <?php endforeach ?>
            </ol>
        </div>
    </div>
    

    也许这可以解决您的问题,因为同一页面包含此注释:

    不支持在同一控制块中混合语法。

    更新2

    在您更新了您的问题后,它现在更清楚了。每个文本行的输出不包含一个元素。相反,它包含多行文本。因此,我的第一个代码没有回显任何内容,因为它在第一个数组元素中找到了 From Account

    因此我们需要搜索字符串From Account 剪切文本行:

    <div class="row">
        <div class="col-12">
            <ol>
                <?php foreach ($text as $key => $texts): ?> 
                    <?php
                    $text = $texts->info()['description'];
                    // search for string
                    $pos = strpos($texts->info()['description'], 'From Account');
                    if ($pos !== false) {
                        // if the string was found cut the text
                        $text = substr($text, 0, $pos);
                    }
                    ?>
                    <li><h6> <?php echo $text ?></h6><<br><br> 
                    </li>
                <?php endforeach ?>
            </ol>
        </div>
    </div>
    

    您可以选择在&lt;?php endforeach ?&gt; 之前添加它以跳过所有以下数组元素:

                    <?php
                    if ($pos !== false) {
                        break;
                    }
                    ?>
    

    注意: @TerryLennox 使用 preg_match 来查找 From Account。这与使用strpos (most prefer avoiding regex) 没有区别。但他的回答包含另一个很好的提示。他使用文本位置信息将文本逐行添加到新数组中。这可能非常有用,具体取决于您的目标如何显示/存储文本。

    【讨论】:

    • thx 但代码不起作用,仍然从图像中获取所有文本
    • 我刚刚从goolge图片下载的图片,所以不是,私人数据哈哈
    • @overflowstack $texts-&gt;info()['description'] 是否包含文本 From Account 或者字符串是否被拆分或空格不是空格?或者您可能需要使用stripos 来克服区分大小写:php.net/manual/function.stripos.php
    • 这里你可以看到代码有效:sandbox.onlinephpfunctions.com/code/…
    • 我更新了我的问题并添加了输出,请看一下
    猜你喜欢
    • 1970-01-01
    • 2017-10-20
    • 2019-04-24
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 2017-11-28
    • 2018-12-08
    • 2020-03-06
    相关资源
    最近更新 更多