当前位置:   article > 正文

AI提取图片里包含的文字信息-解决文字无法复制的痛点_ai 动态图片文字提取不出来

ai 动态图片文字提取不出来

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
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298

在请求参数里的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());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/586243
推荐阅读
相关标签
  

闽ICP备14008679号