手把手0基礎(chǔ)Centos下安裝與部署paddleOcr 教程

!!!以下內(nèi)容為作者原創(chuàng),首發(fā)于掘金平臺(tái)。未經(jīng)原作者同意與許可,任何人、任何組織不得以任何形式轉(zhuǎn)載。原創(chuàng)不易,如果對(duì)您的問(wèn)題提供了些許幫助,希望得到您的點(diǎn)贊支持。

0.paddleOcr簡(jiǎn)介

paddleOcr 是基于paddlepaddle飛槳這一開(kāi)源的深度學(xué)習(xí)平臺(tái)下訓(xùn)練出來(lái)的一個(gè)輪子,它的作用正如名稱:提取并識(shí)別圖片中的文字。
目前paddleOcr 官方已經(jīng)發(fā)布了80+語(yǔ)言的識(shí)別模型,針對(duì)日常的使用來(lái)說(shuō)是足夠了。
下面就以官方的 中英文通用OCR模型 為例,來(lái)一步步教大家如何在centos7的系統(tǒng)中下載、安裝、測(cè)試、部署服務(wù)等全部過(guò)程

下面的教程全程非常詳細(xì),適合0基礎(chǔ)小伙伴們來(lái)學(xué)習(xí)操作。

1.寫在教程前

為什么會(huì)想著寫這樣一篇教程?

其實(shí)paddleOcr的github里已經(jīng)有很詳細(xì)的教程,有能力和基礎(chǔ)的小伙伴完全可以自己看著官方說(shuō)明搞定所有的問(wèn)題。但是對(duì)沒(méi)那么熟悉的小伙伴來(lái)說(shuō)就教程顯得不那么友好,自己在網(wǎng)上東拼西找一些相關(guān)資料,最后還是可能會(huì)卡住在1、2個(gè)小問(wèn)題上,導(dǎo)致無(wú)法部署成功;

在教程的最后我會(huì)將本次參考到的所有資料與鏈接放在下面。

下面直接進(jìn)入本次教程

2.centos下準(zhǔn)備好docker工具

正所謂工欲善其事,并先利其器;我們直接用官方準(zhǔn)備好的docker環(huán)境來(lái)安裝,會(huì)避免掉大部分的問(wèn)題,但是也會(huì)碰到一些小坑,下面會(huì)一一說(shuō)明

centos下找到在docker安裝包并安裝

  • yum list docker-ce --showduplicates | sort -r

可以自己選擇一個(gè)穩(wěn)定的版本安裝,或者不指定版本,直接安裝最新版本
docker-ce.x$6_64.png
  • yum install docker-ce 接下來(lái)就是yum來(lái)安裝docker完成
Pasted Graphic 1.png

啟動(dòng)docker服務(wù)

  • service docker start 啟動(dòng)docker服務(wù)
Lrootelocalhost ~
  • docker --version 查看docker版本,以檢查docker是否正常啟動(dòng)
[root@localhost ~]# docker --version.png
  • systemctl enable docker 配置一下docker服務(wù)開(kāi)機(jī)自啟動(dòng)
Pasted Graphic 4.png

3.下載paddleOcr官方docker鏡像

官方github倉(cāng)庫(kù)地址 官方gitee倉(cāng)庫(kù)地址
官方建議是去github地址上,但github的訪問(wèn)速度懂的都懂。
下面的例子以github地址為例,無(wú)法訪問(wèn)github的小伙伴去gitee中找到替換的地址

創(chuàng)建paddleOcr目錄

該目錄是用于存放paddleOcr鏡像,官方建議是在/home/Projects下
mkdir /home/Projects 創(chuàng)建項(xiàng)目目錄
cd /home/Projects 進(jìn)入項(xiàng)目目錄

下載官方鏡像

docker run --name ppocr  -v $PWD:/paddle --network=host -it paddlepaddle/paddle:latest-dev-cuda10.1-cudnn7-gcc82 /bin/bash
說(shuō)明一下:
官方的docker命令沒(méi)有映射運(yùn)行端口,這里要說(shuō)明一下:官方啟動(dòng)docker的方式為 network=host,即容器內(nèi)用的端口就是宿主機(jī)的端口
復(fù)制代碼

接下來(lái)docker就會(huì)自動(dòng)開(kāi)始下載鏡像了,然后就是漫長(zhǎng)的下載等待,大概下載時(shí)間會(huì)有10分鐘左右

Pasted Graphic 7.png

下載完畢后,會(huì)自動(dòng)進(jìn)入到鏡像內(nèi)部的shell里,進(jìn)入下面這樣的界面中。
0fgest Sha25693072d145036423016038e088490G0340b1299300143d55026€e469487254cdo.png

不用理睬,直接exit退出來(lái)。
Localhost home exit.png

docker ps -a 查看一下docker的運(yùn)行進(jìn)程,發(fā)現(xiàn)這個(gè)這個(gè)剛剛下載來(lái)的ppocr已經(jīng)被關(guān)閉掉了。

Pasted Graphic 11.png

docker start ppocr 重啟這個(gè)ppocr容器

Pasted Graphic 12.png

4.安裝paddlepaddle2.0

之前在0.簡(jiǎn)介里面也說(shuō)了,paddleOcr是基于paddlepaddle這個(gè)平臺(tái)下的,所以它的運(yùn)行理所當(dāng)然離不開(kāi)paddlepaddle這個(gè)平臺(tái)

【很重要】檢查docker內(nèi)的python3以及pip3版本

進(jìn)入docker容器中,一定要檢查一下python3 的版本和 pip3用的版本,要確保版本在3.7及以上,這是官方要求的版本。 但是很坑的是,官方docker你鏡像中竟然是3.5.1 的python3。這里必須手動(dòng)去升級(jí)安裝新版本

docker exec -it ppocr /bin/bash 進(jìn)入docker容器內(nèi)部

[rootelocalhost Projects]# docker exec -it ppocr binbash.png

python3 --version 檢查python3 版本,如圖版本是3.5.1,必須要進(jìn)行升級(jí)

localhost home python3 --version.png

pip3 --version 檢查pip3版本,如果pip3是3.5.1下的,也要跟著一起升級(jí)

Pasted Graphic 15.png

升級(jí)安裝python3

容器內(nèi)已經(jīng)有python3 的源碼安裝文件 在/home 目錄下,有3.7.0 和 3.8.0 我們直接選擇3.8.0 編譯安裝。
E POM..8822084.800 rwon .S.10w R L& 1ee .2.2.0w.png

cd /Python-3.8.0 進(jìn)入到Python-3.8.0目錄下

Pasted Graphic 17.png

./configure 編譯器會(huì)執(zhí)行一些安裝前檢查,稍等片刻就會(huì)檢查完成。

ocalnost.png

make && make install 源碼安裝,稍等幾分鐘,等待安裝完成。

(cd usrlocooini in -s pythons.i pythons.png

安裝完成,重新檢查一下python3,pip3版本,確保版本已經(jīng)升級(jí)到3.8.0
Localhost homePython-3.8.0 python3 --version.png
pipJ--verston.png

【很重要】更新用戶環(huán)境變量參數(shù)

安裝一個(gè)vim,方便容器內(nèi)進(jìn)行文本編輯

apt-get update
apt-get install vim
復(fù)制代碼
locolrost apt-qet update.png
ne mone or2 T vir atkpr2 1vie stasp MIRIERNGRe 3Y2 1VIR ROSFY.png

vi ~/.bashrc 修改.bashrc中指定的python環(huán)境變量
在文件編輯中將所有的 python3.5.1 的配置全部刪除掉,將下面截圖紅框處的內(nèi)容刪除掉并保存

Pasted Graphic 29.png

source ~/.bashrc 重新生效配置文件

localhost.png

升級(jí)pip3

解決掉python3版本問(wèn)題后,就要安裝paddleOcr 所需要的環(huán)境paddlepaddle2.0

pip3 install --upgrade pip 升級(jí)一下 pip3 (官方安裝指導(dǎo))
稍等片刻即可

Pasted Graphic 22.png

安裝paddlepaddle2.0

這一步官方的指導(dǎo)里面是區(qū)分gpu 還是 cpu版本,下面的例子都是以cpu版本為例。 (請(qǐng)需要安裝gpu版本的小伙伴執(zhí)行到此處稍微移步到官方文檔鏈接中去找一下gpu版本的安裝指令)

python3 -m pip install paddlepaddle==2.0.0 -i https://mirror.baidu.com/pypi/simple
復(fù)制代碼

稍微等待幾分鐘的下載與更新
Pasted Graphic 23.png

cd /home 切換回目錄下

clone PaddleOcr 倉(cāng)庫(kù)代碼

【推薦】git clone https://github.com/PaddlePaddle/PaddleOCR
如果無(wú)法訪問(wèn)github 的小伙伴們也可以通過(guò)gitee倉(cāng)庫(kù)里面將源碼下載下來(lái):
git clone https://gitee.com/paddlepaddle/PaddleOCR
復(fù)制代碼
tocolhost.png

安裝第三方庫(kù)

cd /home/PaddleOCR 切換到PaddleOcr目錄下:

Pasted Graphic 25.png

pip3 install -r requirements.txt 安裝第三方庫(kù)

進(jìn)入稍微漫長(zhǎng)的下載等待。這一步我在實(shí)際安裝過(guò)程中因?yàn)榫W(wǎng)絡(luò)原因失敗過(guò)一次,請(qǐng)大家耐心安裝,如遇 HTTPSConnectionPool Read timed out. 這樣的問(wèn)題,請(qǐng)多嘗試安裝幾次,等其安裝完成。

Kfre PeanPennS.TA Ce 29)1 N0).png

5.下載官方模型

以官方的服務(wù)器端模型為例說(shuō)明。 (官方另為模型包更小的適合移動(dòng)端的模型,感興趣的小伙伴小移步官方的文檔說(shuō)明中 github.com/PaddlePaddl…

docker 鏡像中創(chuàng)建模型目錄

mkdir /home/PaddleOCR/inference && cd /home/PaddleOCR/inference 在paddleOCR下創(chuàng)建inference模型目錄

lecelrost hosefotdleo Rinference leoe2.png

下載、解壓模型

官方模型分為檢測(cè),方向,識(shí)別模型,分別下載與解壓

下載檢測(cè)模型  wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_det_infer.tar
下載方向分類器 wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar
下載識(shí)別模型 wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_rec_infer.tar

解壓壓縮包

tar xf ch_ppocr_mobile_v2.0_cls_infer.tar
tar xf ch_ppocr_server_v2.0_det_infer.tar 
tar xf ch_ppocr_server_v2.0_rec_infer.tar
復(fù)制代碼

解壓完成后的目錄如下
Pasted Graphic 34.png

6.單張圖片識(shí)別測(cè)試

回到/home/paddleOCR目錄下

cd /home/PaddleOCR

圖片測(cè)試

用官方自帶的圖片來(lái)測(cè)試識(shí)別,官方自帶圖片目錄為/home/PaddleOCR/doc/imgs

測(cè)試命令為:
python3 tools/infer/predict_system.py --image_dir="./doc/imgs/11.jpg" --det_model_dir="./inference/ch_ppocr_server_v2.0_det_infer/"  --rec_model_dir="./inference/ch_ppocr_server_v2.0_rec_infer/" --cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer/" --use_angle_cls=True --use_space_char=True --use_gpu=False
復(fù)制代碼

以下分別是原圖,識(shí)別后標(biāo)識(shí)圖,以及識(shí)別結(jié)果

純臻營(yíng)養(yǎng)護(hù)發(fā)素.png
純臻營(yíng)養(yǎng)護(hù)發(fā)素.png
Pasted Graphic 35.png

7.服務(wù)部署

單張圖片測(cè)試通過(guò)后,我們就需要把服務(wù)以WEB方式部署上,以供其它服務(wù)以接口形式來(lái)調(diào)用了。

PaddleHub Server 服務(wù)部署

這種部署形式也是官方推薦的部署方式之一。

安裝paddlehub 環(huán)境

在docker鏡像中執(zhí)行以下命令
pip3 install paddlehub==1.8.3 --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple
稍等片刻即可下載完成

Pasted Graphic 38.png

修改部署參數(shù)文件

部署參數(shù)文件地址為docker鏡像中: /home/PaddleOCR/deploy/hubserving/ocr_system 下的 params.py

用vi 打開(kāi)params.py ,將下圖紅框處的3個(gè)文件地址分別修改為下面地址:
/home/PaddleOCR/inference/ch_ppocr_server_v2.0_det_infer/
/home/PaddleOCR/inference/ch_ppocr_server_v2.0_rec_infer/
/home/PaddleOCR/inference/ch_ppocr_mobile_v2.0_cls_infer/
其它參數(shù)暫時(shí)不需要修改
復(fù)制代碼
fo. .olgorktr.png

安裝服務(wù)模塊

安裝檢測(cè)+識(shí)別串聯(lián)服務(wù)模塊:
hub install deploy/hubserving/ocr_system/

localhost.png

安裝flask

下面使用flask 部署web框架 pip3 install flask

snaoed aikcoor.12 tn Maeforoin(enheny waftepol Kfroe faty c.e.1).png

安裝flask-cors

pip3 install flask-cors

Pasted Graphic 43.png

新建web服務(wù)程序

在 /home/PaddleOCR/tools 目錄下新建一個(gè)新的py文件,文件名為test_myocr.py 并且給權(quán)限為 775
testmyocr.py的內(nèi)容如下:

# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
__dir__ = os.path.dirname(os.path.abspath(__file__))
sys.path.append(__dir__)
sys.path.append(os.path.abspath(os.path.join(__dir__, '..')))

from ppocr.utils.logging import get_logger
logger = get_logger()

import cv2
import numpy as np
import time
from PIL import Image
from ppocr.utils.utility import get_image_file_list
from tools.infer.utility import draw_ocr, draw_boxes

import requests
import json
import base64

from flask import Flask,request
from flask_cors import CORS

import requests
app = Flask(__name__)
CORS(app)  # 解決跨域問(wèn)題

def cv2_to_base64(image):
    return base64.b64encode(image).decode('utf8')

def draw_server_result(image_file, res):
    img = cv2.imread(image_file)
    image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    if len(res) == 0:
        return np.array(image)
    keys = res[0].keys()
    if 'text_region' not in keys:  # for ocr_rec, draw function is invalid 
        logger.info("draw function is invalid for ocr_rec!")
        return None
    elif 'text' not in keys:  # for ocr_det
        logger.info("draw text boxes only!")
        boxes = []
        for dno in range(len(res)):
            boxes.append(res[dno]['text_region'])
        boxes = np.array(boxes)
        draw_img = draw_boxes(image, boxes)
        return draw_img
    else:  # for ocr_system
        logger.info("draw boxes and texts!")
        boxes = []
        texts = []
        scores = []
        for dno in range(len(res)):
            boxes.append(res[dno]['text_region'])
            texts.append(res[dno]['text'])
            scores.append(res[dno]['confidence'])
        boxes = np.array(boxes)
        scores = np.array(scores)
        draw_img = draw_ocr(
            image, boxes, texts, scores, draw_txt=True, drop_score=0.5)
        return draw_img

@app.route("/test")
def test():
    return 'Hello World!'

@app.route("/myocr", methods=["POST"] )
def myocr():
    # 輸入?yún)?shù)
    image_file = request.files['file']
    basepath = os.path.dirname(__file__)

    logger.info("{} basepath".format(basepath))

    savepath = os.path.join(basepath, image_file.filename)
    image_file.save(savepath)
    img = open(savepath, 'rb').read()
    if img is None:
        logger.info("error in loading image:{}".format(image_file))

    # 轉(zhuǎn)為 base64
    data = {'images': [cv2_to_base64(img)]}
    # 發(fā)送請(qǐng)求
    url = "http://127.0.0.1:8866/predict/ocr_system"
    headers = {"Content-type": "application/json"}
    r = requests.post(url=url, headers=headers, data=json.dumps(data))

    # 返回結(jié)果
    res = r.json()["results"][0]
    logger.info(res)
    return  json.dumps(res)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
復(fù)制代碼

啟動(dòng)服務(wù)

服務(wù)分為hub服務(wù)、web服務(wù)

啟動(dòng)hub服務(wù)

【很重要】 export PATHONPATH=.這步很重要,血淚教訓(xùn)哇;

如果少了這一步設(shè)置環(huán)境變量,在下面的執(zhí)行中會(huì)報(bào)錯(cuò),提示找不到tools module

hub serving start -m ocr_system & 成功會(huì)出現(xiàn)如下說(shuō)明

lecalhost oneMolrod reioasoel hdb stcog Srart KotL.png

啟動(dòng)web服務(wù)

cd /home/PaddleOCR/tools 目錄切換到tools下 python3 test_myocr.py & 啟動(dòng)web服務(wù),啟動(dòng)成功會(huì)出現(xiàn)如下說(shuō)明

grp BrLNg sIPeeTECA ss drgrecene. oleore see on olfes or Merip.png

8.服務(wù)測(cè)試

Postman工具調(diào)用測(cè)試

使用postman向 5000端口去發(fā)起請(qǐng)求,可以看到服務(wù)正常返回識(shí)別的結(jié)果
Pasted Graphic 46.png

Vue簡(jiǎn)單頁(yè)面測(cè)試

使用vue寫一個(gè)簡(jiǎn)單的圖片上傳頁(yè)面,后端接口負(fù)責(zé)轉(zhuǎn)發(fā)數(shù)據(jù)與請(qǐng)求到5000接口中 這塊后面有時(shí)間再單獨(dú)寫篇介紹下

截屏2021-07-19 22.36.19.png

9.性能分析

測(cè)試機(jī)配置

測(cè)試機(jī)器是在實(shí)體機(jī)器中使用VM虛擬化出來(lái)的

實(shí)體機(jī):
cpu: AMD Ryzen 5 2600X Six-Core Processor
內(nèi)存:32G
操作系統(tǒng):window10 x64

虛擬Centos:
處理器:4核單線程
內(nèi)存:8GB
操作系統(tǒng):Centos 7.8
復(fù)制代碼

以下解析時(shí)間僅供參考
在沒(méi)做任何優(yōu)化情況下,且不考慮網(wǎng)絡(luò)傳輸速度的影響,單張6.中的官方自帶測(cè)試圖片,解析時(shí)間分別為:

docker中直測(cè):11秒
postman:17秒
vue中:18秒
復(fù)制代碼

10.參考資料

PaddleOCR github
PaddleOCR安裝與實(shí)踐(CPU版)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,530評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 176,407評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,981評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,759評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,204評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,415評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,955評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,650評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,892評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,675評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容