AI提取图片里包含的文字信息-解决文字无法复制的痛点【玩转华为云】

举报
DS小龙哥 发表于 2022/02/14 14:52:11 2022/02/14
【摘要】 当前利用华为云提供的 通用文字识别接口,识别图片里的文本内容,方便复制文字。这个功能QQ上也集成了,使用很方便,这里利用华为云的接口实现一个与QQ类似的功能,截图之后识别图片里包含的文本内容。

1. 前言

平时工作中编写开发技术文档,或者学生在编写论文时,经常会上网搜索一些参考文献、文档。

比如: 上网搜索相似的内容参考一下或者引用别人的一段文字,有时候看到一篇较好的内容想要保存等等。

这个过程中会发现,很多网站的提供的页面都是不能复制粘贴的,或者直接是图片形式提供,为了方便能获取这些文字,当前就利用华为云提供的 通用文字识别接口,识别图片里的文本内容,方便复制文字。这个功能QQ上也集成了,使用很方便,这里利用华为云的接口实现一个与QQ类似的功能,截图之后识别图片里包含的文本内容。

这个文字识别接口里不仅仅有通用文字识别功能,还支持很多其他功能:比如身份证、驾驶证、保险单、手写文本、火车票,行驶证…等等功能。还支持用户自定义识别模板,指定需要识别的关键字段,实现用户特定格式图片的自动识别和结构化提取。

image-20220214142233066

2. 文本识别接口使用介绍

2.1 开通服务

地址: https://console.huaweicloud.com/ocr/?region=cn-north-4#/ocr/overview

image-20220214142605756

这个文字识别服务是按调用次数计费的,每个用户每月有1000次的免费调用次数,开通服务后就可以使用。

2.2 接口地址

官网帮助文档: https://support.huaweicloud.com/api-ocr/ocr_03_0042.html

POST https://{endpoint}/v2/{project_id}/ocr/general-text

示例:
https://ocr.cn-north-4.myhuaweicloud.com/v2/0e5957be8a00f53c2fa7c0045e4d8fbf/ocr/general-text

请求头:
{
 "X-Auth-Token": "******",
 "Content-Type": "application/json;charset=UTF-8"
}

请求体:
{
 "image": ----这是图片的bas64编码
}

响应结果:
{
 "result": {
  "words_block_count": 13,
  "words_block_list": [
   {
    "words": "撤,还是不撤?",
    "location": [
     [
      43,
      39
     ],
     [
      161,
      39
     ],
     [
      161,
      60
     ],
     [
      43,
      60
     ]
    ]
   },
   {
    "words": "让我更骄傲的是公司在大灾面前的表现。",
    "location": [
     [
      72,
      95
     ],
     [
      332,
      95
     ],
     [
      332,
      113
     ],
     [
      72,
      113
     ]
    ]
   },
   {
    "words": "2011年3月11日14时46分,日本东北部海域发生里氏9.0级",
    "location": [
     [
      71,
      122
     ],
     [
      482,
      122
     ],
     [
      482,
      142
     ],
     [
      71,
      142
     ]
    ]
   },
   {
    "words": "地震并引发海啸。那一刻,我们正在距离东京100公里的热海开会,",
    "location": [
     [
      41,
      149
     ],
     [
      481,
      149
     ],
     [
      481,
      171
     ],
     [
      41,
      171
     ]
    ]
   },
   {
    "words": "感觉“咚”",
    "location": [
     [
      42,
      180
     ],
     [
      114,
      180
     ],
     [
      114,
      199
     ],
     [
      42,
      199
     ]
    ]
   },
   {
    "words": "地被震了一下。面对地震,",
    "location": [
     [
      115,
      178
     ],
     [
      296,
      178
     ],
     [
      296,
      199
     ],
     [
      115,
      199
     ]
    ]
   },
   {
    "words": "大家都很镇定,",
    "location": [
     [
      300,
      179
     ],
     [
      400,
      179
     ],
     [
      400,
      197
     ],
     [
      300,
      197
     ]
    ]
   },
   {
    "words": "直到看到电",
    "location": [
     [
      405,
      179
     ],
     [
      483,
      179
     ],
     [
      483,
      196
     ],
     [
      405,
      196
     ]
    ]
   },
   {
    "words": "视上触目惊心的画面:15时 25 分,海啸到达陆前高田市海岸;15时",
    "location": [
     [
      41,
      206
     ],
     [
      485,
      206
     ],
     [
      485,
      228
     ],
     [
      41,
      228
     ]
    ]
   },
   {
    "words": "26分,海啸到达陆前高田市中心;15时43分,陆前高田市依稀只能",
    "location": [
     [
      40,
      234
     ],
     [
      486,
      234
     ],
     [
      486,
      258
     ],
     [
      40,
      258
     ]
    ]
   },
   {
    "words": "看到四层高的市府大楼的屋顶,一瞬间,城镇就变成了汪洋……对",
    "location": [
     [
      40,
      262
     ],
     [
      487,
      262
     ],
     [
      487,
      287
     ],
     [
      40,
      287
     ]
    ]
   },
   {
    "words": "我来说,地震跟家常便饭一样,可眼前的灾难比以往任何一次都要",
    "location": [
     [
      40,
      292
     ],
     [
      487,
      292
     ],
     [
      487,
      317
     ],
     [
      40,
      317
     ]
    ]
   },
   {
    "words": "惨烈,完全超出了我的预期。",
    "location": [
     [
      41,
      326
     ],
     [
      231,
      326
     ],
     [
      231,
      345
     ],
     [
      41,
      345
     ]
    ]
   }
  ],
  "direction": -1
 }
}

在请求参数里的X-Auth-Token参数比较重要,调用华为云的任何API接口都需要这个参数,获取方式可以看前面的文章。比如这篇文章: https://support.huaweicloud.com/api-ocr/ocr_03_0005.html

2.3 在线调试接口

地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=OCR&api=RecognizeGeneralText

使用调试接口想体验识别效果,图片的数据支持base64编码、http网络图片地址传入,测试非常方便。

关于获取图片base64编码的方式,在文档里也有介绍,直接通过浏览器获取。

image-20220214144146775

image-20220214143945486

3. 实现代码

代码采用QT编写的,请求API接口实现调用。其他语言方法是一样的。

3.1 实现效果

image-20220214144917259

image-20220214144825170

3.2 核心代码

//解析反馈结果
void Widget::replyFinished(QNetworkReply *reply)
{
    QString displayInfo="";
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    //读取所有数据
    QByteArray replyData = reply->readAll();

    qDebug()<<"状态码:"<<statusCode;
    qDebug()<<"反馈的数据:"<<QString(replyData);

    //更新token
    if(function_select==3)
    {
        displayInfo="token 更新失败.";
        //读取HTTP响应头的数据
        QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs();
        qDebug()<<"HTTP响应头数量:"<<RawHeader.size();
        for(int i=0;i<RawHeader.size();i++)
        {
            QString first=RawHeader.at(i).first;
            QString second=RawHeader.at(i).second;
            if(first=="X-Subject-Token")
            {
                Token=second.toUtf8();
                displayInfo="token 更新成功.";

                //保存到文件
                SaveDataToFile(Token);
                break;
            }
        }
        QMessageBox::information(this,"提示",displayInfo,QMessageBox::Ok,QMessageBox::Ok);
        return;
    }

    //判断状态码
    if(200 != statusCode)
    {
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            {
                QString error_str="";
                QJsonObject obj = document.object();
                QString error_code;
                //解析错误代码
                if(obj.contains("error_code"))
                {
                    error_code=obj.take("error_code").toString();
                    error_str+="错误代码:";
                    error_str+=error_code;
                    error_str+="\n";
                }
                if(obj.contains("error_msg"))
                {
                    error_str+="错误消息:";
                    error_str+=obj.take("error_msg").toString();
                    error_str+="\n";
                }

                //显示错误代码
                QMessageBox::information(this,"提示",error_str,QMessageBox::Ok,QMessageBox::Ok);
            }
         }
        return;
    }

    //结果返回
    if(function_select==1)
    {
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            {
                QJsonObject obj = document.object();
                QString error_code;
                //解析
                if(obj.contains("result"))
                {
                    QJsonObject obj1=obj.take("result").toObject();

                    QString bank_name;
                    QString card_number;
                    QString type;

                    QString text;
                    if(obj1.contains("bank_name"))
                    {
                        bank_name=obj1.take("bank_name").toString();
                    }
                    if(obj1.contains("card_number"))
                    {
                        card_number=obj1.take("card_number").toString();
                    }
                    if(obj1.contains("type"))
                    {
                        type=obj1.take("type").toString();
                    }


                    text="发卡行:"+bank_name+"\n";
                    text+="卡号:"+card_number+"\n";
                    text+="卡类型:"+type+"\n";

                    ui->plainTextEdit->setPlainText(text);
                }
            }
        }
    }

    //结果返回
    if(function_select==2)
    {
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            {
                QJsonObject obj = document.object();
                QString error_code;
                //解析
                if(obj.contains("result"))
                {
                    QJsonObject obj1=obj.take("result").toObject();

                    int words_block_count;
                    QString text="";
                    if(obj1.contains("words_block_count"))
                    {
                        words_block_count=obj1.take("words_block_count").toInt();

                       // text=QString("识别到%1行文本.\n").arg(words_block_count);
                    }

                    if(obj1.contains("words_block_list"))
                    {
                        QJsonArray array=obj1.take("words_block_list").toArray();
                        for(int i=0;i<array.size();i++)
                        {
                            QJsonObject obj2=array.at(i).toObject();
                            if(obj2.contains("words"))
                            {
                                text+=obj2.take("words").toString();
                                text+="\n";
                            }
                        }
                    }

                    ui->plainTextEdit->setPlainText(text);
                }
            }
        }
    }
}

/*
功能: 获取token
*/
void Widget::GetToken()
{
    //表示获取token
    function_select=3;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //获取token请求地址
    requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
                 .arg(SERVER_ID);

    //自己创建的TCP服务器,测试用
    //requestUrl="http://10.0.0.6:8080";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    QString text =QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":"
    "{\"user\":{\"domain\": {"
    "\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
    "\"scope\":{\"project\":{\"name\":\"%4\"}}}}")
            .arg(MAIN_USER)
            .arg(IAM_USER)
            .arg(IAM_PASSWORD)
            .arg(SERVER_ID);

    //发送请求
    manager->post(request, text.toUtf8());
}

//粘贴图片
void Widget::on_pushButton_copy_clicked()
{
    QClipboard *clipboard = QApplication::clipboard();
    const QMimeData *mimeData = clipboard->mimeData();
    if (mimeData->hasImage())
    {
        //将图片数据转为QImage
        QImage img = qvariant_cast<QImage>(mimeData->imageData());
        if(!img.isNull())
        {
           ui->widget->SetImage(img);
        }
    }
}

//获取图片里的文字信息
void  Widget::getTextInfo(QImage image)
{
    function_select=2;
    QString requestUrl;
    QNetworkRequest request;

    //存放图片BASE64编码
    QString imgData;

    //设置请求地址
    QUrl url;

    //人脸搜索请求地址
    requestUrl = QString("https://ocr.%1.myhuaweicloud.com/v2/%2/ocr/general-text")
            .arg(SERVER_ID)
            .arg(PROJECT_ID);

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));

    //将图片进行Base64编码
    imgData = QString(toBase64(image)); //编码后的图片大小不超过2M
    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);
    request.setUrl(url);

    QString post_param=QString
               ("{"
                 "\"image\": \"%1\""
                "}").arg(imgData);

    //发送请求
    manager->post(request, post_param.toUtf8());
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。