Introduction

Introduction


OpenCV擦俐,或稱開源計(jì)算機(jī)視覺庫目派,是一個(gè)基于BSD開源協(xié)議憾股,包含許多種計(jì)算機(jī)視覺算法的開源庫。此文檔所描述的OpenCV 2.x API實(shí)質(zhì)上是C++的API庵佣,與基于C語言的OpenCV 1.x不同(C語言的API已被廢棄,自O(shè)penCV 2.4之后的發(fā)行版便再也沒用C編譯器做過測(cè)試)汛兜。

OpenCV擁有模塊化結(jié)構(gòu)巴粪,也即軟件包包括了許多動(dòng)態(tài)或者靜態(tài)庫。例如以下是一些可用模組粥谬。

  • 核心功能(core):一個(gè)緊湊的模塊肛根,定義了基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),包括稠密多維數(shù)組Mat以及一些可被其它模塊用到的函數(shù)
  • 圖像處理(imgproc):一個(gè)圖像處理模塊漏策,包含線性和非線性濾波器派哲,幾何圖像變換(大小改變(resize),仿射(affine)以及扭曲透視,基于泛型表的重新映射)掺喻,色彩空間轉(zhuǎn)換芭届,直方圖等等储矩。
  • 視頻分析(video):視頻分析包括了運(yùn)動(dòng)估計(jì),背景減法褂乍,對(duì)象追蹤等散發(fā)
  • 相機(jī)標(biāo)定及三維重建(calib3d):基本的多視圖幾何算法持隧,單目雙目相機(jī)標(biāo)定,對(duì)象姿態(tài)估計(jì)逃片,雙目立體匹配算法等屡拨,還包括一些用于三維重建的元素。
  • 二維特征框架(features2d):顯著特征檢測(cè)器题诵,描述符以及描述符匹配器
  • 對(duì)象檢測(cè)(objdetect):對(duì)象檢測(cè)以及預(yù)先定義好的類的實(shí)例(比如臉洁仗、眼睛、被子性锭、行人赠潦、車輛等等)
  • 高級(jí)用戶界面和媒體流I/O操作(highgui):簡(jiǎn)單易用的一個(gè)基本UI界面
  • 視頻輸入/輸出(videoio):簡(jiǎn)單易用的視頻捕捉和解碼模塊
  • ……以及一些有用的其它模塊,比如flann和Google test wrappers草冈,Python binding等她奥。
    接下來的文檔會(huì)詳細(xì)介紹每個(gè)模塊的功能及用法。但首先請(qǐng)熟悉本庫中最基礎(chǔ)的API概念及其用法怎棱。

API概念(API Concept)

cv命名空間(cv Namespace)


OpenCV所有的類和函數(shù)都放置在cv這個(gè)命名空間里的哩俭,因此想要在你的代碼中使用OpenCV的功能,請(qǐng)使用cv::標(biāo)示符或者直接使用:using namespace cv;

#include "opencv2/core.hpp"
...
cv::Mat H = cv::findHomography(points1, points2, cv::RANSAC, 5);
...

或者是:

#include "opencv2/core.hpp"
using namespace cv;
...
Mat H = findHomography(points1, points2, RANSAC, 5 );
...

現(xiàn)有或者在將來可能會(huì)出現(xiàn)一些外部名稱和STL相同(沖突)拳恋,因此凡资,請(qǐng)使用明確的cv::標(biāo)示符已解決名稱沖突:

Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a);
a /= std::log(2.);

std::cv::中均有log()函數(shù)

自動(dòng)內(nèi)存管理(Automatic Memory Management)


OpenCV對(duì)內(nèi)存實(shí)行自動(dòng)管理

首先,被大多數(shù)函數(shù)或者方法調(diào)用的std::vectorcv::Mat以及其它數(shù)據(jù)結(jié)構(gòu)有析構(gòu)函數(shù)谬运,在需要時(shí)釋放底層內(nèi)存緩沖區(qū)隙赁。這意味著析構(gòu)函數(shù)并需要總是釋放Mat的內(nèi)存緩沖,它們考慮到了可能的數(shù)據(jù)共享梆暖,析構(gòu)函數(shù)與矩陣數(shù)據(jù)緩存區(qū)相關(guān)的引用計(jì)數(shù)器(reference counter)遞減伞访。當(dāng)且僅當(dāng)引用計(jì)數(shù)到了0的情況下,緩存被釋放轰驳,也即是說厚掷,沒有其它結(jié)構(gòu)引用同一緩沖區(qū)。與之相似级解,當(dāng)一個(gè)Mat的實(shí)例被復(fù)制冒黑,實(shí)際上并沒有數(shù)據(jù)復(fù)制,取而代之的是引用計(jì)數(shù)器遞增以記住同一數(shù)據(jù)的另一個(gè)變體勤哗。而Mat::clone()的方法就是創(chuàng)建一個(gè)矩陣的完整副本(內(nèi)存拷貝)薛闪。參考以下例子:

//創(chuàng)建一個(gè)8Mb的矩陣
 Mat A(1000, 1000, CV_64F);

 //為相同矩陣創(chuàng)建另一個(gè)頭部;
 //這個(gè)是立即操作,和矩陣大小無關(guān)俺陋。
 Mat B = A;

 //使用A中的第三行數(shù)據(jù)創(chuàng)建另一個(gè)頭部豁延,創(chuàng)建過程中不存在數(shù)據(jù)復(fù)制昙篙。
 Mat C = B.row(3);

 //現(xiàn)在創(chuàng)建一個(gè)獨(dú)立的矩陣副本
 Mat D = B.clone();
 
 //復(fù)制B的第五行到C,實(shí)質(zhì)上是拷貝了A的第五行到A的第三行诱咏。 
 B.row(5).copyTo(C);

//現(xiàn)在讓A和D共享數(shù)據(jù)苔可;剛剛修改的那個(gè)版本依舊被B和C所引用。
A = D;

//現(xiàn)在讓B成為一個(gè)空矩陣(不再引用內(nèi)存緩沖區(qū))袋狞,
//但剛剛修改的版本依舊被C所引用著焚辅,盡管C僅僅是A原始數(shù)據(jù)中的單獨(dú)一行。
 B.release();

 //最終苟鸯,對(duì)C做一個(gè)完整的復(fù)制同蜻,結(jié)果剛剛被修改過的那個(gè)矩陣被釋放,
 //因?yàn)橐呀?jīng)沒有任何引用了早处。

 C = C.clone();

可以看出湾蔓,使用Mat以及其它數(shù)據(jù)結(jié)構(gòu)是非常簡(jiǎn)單的,但是對(duì)于沒有考慮到自動(dòng)內(nèi)存管理的其它高級(jí)類和用戶定義的數(shù)據(jù)類型呢砌梆?對(duì)于它們默责,OpenCV提供了cv::Ptr這樣一個(gè)模板類,與C++11中的std::shared_ptr有些相像咸包。所以桃序,不使用普通指針:

T* ptr = new T(...);

你可以使用:

Ptr<T> ptr(new T(...));

或者是

Ptr<T> ptr = makePtr<T>(...)

Ptr<T>封裝了一個(gè)指向T實(shí)例的指針和與指針相關(guān)聯(lián)的引用計(jì)數(shù)器。

輸出數(shù)據(jù)的自動(dòng)分配 (Automatic Allocation of the Output Data)


OpenCV自動(dòng)釋放內(nèi)存烂瘫,并在大多數(shù)時(shí)間自動(dòng)為輸出函數(shù)參數(shù)分配內(nèi)存媒熊。因此,如果函數(shù)具有一個(gè)或多個(gè)輸入數(shù)組(cv :: Mat實(shí)例)和一些輸出數(shù)組坟比,則會(huì)自動(dòng)分配或重新分配輸出數(shù)組泛释。輸出數(shù)組的大小和類型由輸入數(shù)組的大小和類型決定。如果需要温算,函數(shù)會(huì)采用額外的參數(shù)來幫助確定輸出數(shù)組屬性。
例如:

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
int main(int, char**)
{
    VideoCapture cap(0);
    if(!cap.isOpened()) return -1;
    Mat frame, edges;
    namedWindow("edges", WINDOW_AUTOSIZE);
    for(;;)
    {
        cap >> frame;
        cvtColor(frame, edges, COLOR_BGR2GRAY);
        GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
        Canny(edges, edges, 0, 30, 3);
        imshow("edges", edges);
        if(waitKey(30) >= 0) break;
    }
    return 0;
}

由于視頻幀分辨率和比特深度對(duì)于視頻捕獲模塊是已知的间影,所以陣列幀由>>運(yùn)算符自動(dòng)分配注竿。數(shù)組edge由cvtColor函數(shù)自動(dòng)分配。它具有與輸入數(shù)組相同的大小和位深度魂贬。通道數(shù)為1巩割,因?yàn)轭伾D(zhuǎn)換代碼cv::COLOR_BGR2GRAY被傳遞,這意味著顏色將轉(zhuǎn)邊為灰度圖付燥。請(qǐng)注意宣谈,在第一次執(zhí)行循環(huán)體時(shí),frame和edge僅分配一次键科,因?yàn)橹笏械膸╢rame)都具有相同的分辨率闻丑。如果以某種方式更改視頻分辨率漩怎,則會(huì)自動(dòng)重新分配陣列。

該技術(shù)實(shí)現(xiàn)的關(guān)鍵部分是Mat::create方法嗦嗡。它需要所需的數(shù)組大小和類型勋锤。如果數(shù)組已具有指定的大小和類型,則該方法不執(zhí)行任何操作侥祭。否則叁执,它釋放先前分配的數(shù)據(jù)(如果有的話)(這部分涉及遞減引用計(jì)數(shù)器并將其與零比較),然后分配所需大小的新緩沖區(qū)矮冬。大多數(shù)函數(shù)為每個(gè)輸出數(shù)組調(diào)用Mat::create方法谈宛,因此實(shí)現(xiàn)了自動(dòng)輸出數(shù)據(jù)分配。

值得一些注意的是cv::mixChannels胎署,cv::RNG::fill吆录,以及一些其他函數(shù)和方法例外。它們無法分配輸出數(shù)組硝拧,因此必須提前執(zhí)行此操作径筏。

飽和算法(Saturation Arithmetics)


作為一個(gè)計(jì)算機(jī)視覺庫,OpenCV需要處理大量的圖像像素障陶,圖像通常會(huì)以8-16位的緊湊方式編入每個(gè)通道滋恬,形成具有最大值和最小值的區(qū)間范圍。此外還有一些必要的圖像處理操作抱究,例如色彩空間轉(zhuǎn)換恢氯,亮度、對(duì)比度鼓寺、銳度調(diào)節(jié)勋拟,復(fù)雜修改(bicubic,Lanczos)能產(chǎn)生超出有效范圍的數(shù)值妈候。如果僅存儲(chǔ)結(jié)果的低8(16)位敢靡,可能會(huì)導(dǎo)致視覺偽影,并可能影響更進(jìn)一步的圖像分析苦银。為了解決這個(gè)問題啸胧,飽和算法(saturation arithmetics)應(yīng)運(yùn)而生。如存儲(chǔ)數(shù)值R幔虏,操作的結(jié)果是轉(zhuǎn)化成8bit的圖像纺念,以便能在0-255范圍內(nèi)找到最接近的數(shù)值:
I(x,y)=min(max(round(r),0),255)
相似的規(guī)則應(yīng)用在有符號(hào)8位、無符號(hào)16位想括、有符號(hào)16位類型中陷谱。此語義在庫中具有通用性,在C++代碼中是通過類似于標(biāo)準(zhǔn)C++操作符saturate_cast<>函數(shù)實(shí)現(xiàn)的瑟蜈。見下文所提供的實(shí)現(xiàn)公式:

I.at<uchar>(y, x) = saturate_cast<uchar>(r);

這里的cv::uchar是一個(gè)OpenCV 8bit的無符號(hào)類型烟逊。在SIMD的優(yōu)化代碼里渣窜,以及如SSE2的操作指南中的paddusb、packuswb等等都在使用這種類型焙格。在其幫助下图毕,它們達(dá)到了和C++中一樣的高效表現(xiàn)。

注意: 飽和算法不適用于32位的整型結(jié)果

固定像素類型和對(duì)模板的限制使用(Fixed Pixel Types. Limited Use of Templates)


模板是C++中一個(gè)非常重要的特性眷唉,它可以實(shí)現(xiàn)非常強(qiáng)大予颤、高效且安全的數(shù)據(jù)結(jié)構(gòu)和算法。但是模板的濫用會(huì)導(dǎo)致編譯時(shí)間的顯著增加冬阳、內(nèi)存占用過大等問題蛤虐。而且大量使用模板使會(huì)接口和實(shí)現(xiàn)很難分離,模板對(duì)于一些基礎(chǔ)算法還好肝陪,但是涉及到計(jì)算機(jī)視覺單個(gè)算法就有成百上千行來說卻很累贅驳庭。正因如此,同時(shí)也為了其它語言接口(如Python氯窍、Java饲常、Matlab,這些語言不支持模板或者支持的很有限)開發(fā)的簡(jiǎn)便性狼讨,當(dāng)前OpenCV的實(shí)現(xiàn)是基于的多態(tài)和模板上的運(yùn)行時(shí)調(diào)度贝淤。在某些時(shí)候,運(yùn)行時(shí)調(diào)度很慢(如訪問像素的操作)政供、無法訪問(通常是Ptr<>的實(shí)現(xiàn))或者就是不方便(saturate_cast<>())播聪,實(shí)現(xiàn)時(shí)就小的模板類,方法和函數(shù)布隔。當(dāng)前版本中的OpenCV模板使用時(shí)受限制的离陶。
故OpenCV庫可操作性的數(shù)據(jù)類型是有限的,為以下類型之一:

  • 8-bit 無符號(hào)整形(uchar)
  • 8-bit 有符號(hào)整形(schar)
  • 16-bit 無符號(hào)整形(ushort)
  • 16-bit 有符號(hào)整形(short)
  • 32-bit 有符號(hào)整形(int)
  • 32-bit 浮點(diǎn)型(float)
  • 64-bit 浮點(diǎn)型(double)
  • 所有元素都是同一數(shù)據(jù)類型(以上7種之一)的由幾個(gè)元素組成的一個(gè)元組(tuple)
  • 由以上元組所組成的單位數(shù)組(array)就叫做多通道數(shù)組衅檀。與單位元素都是標(biāo)量的單通道數(shù)組相對(duì)立招刨。通道可能的最大數(shù)是由CV_CN_MAX這個(gè)常量定義的,當(dāng)前是512哀军。
    針對(duì)如上基本類型定義了如下枚舉:
enum { CV_8U    =   0,
       CV_8S    =   1,
       CV_16U   =   2,
       CV_16S   =   3,
       CV_32S   =   4,
       CV_32F   =   5,
       CV_64F   =   6
       };

多通道(n通道)則可據(jù)如下選項(xiàng)定義:

  • CV_8UC1 ... CV_64FC4 常量 (通道數(shù)1-4)
  • CV_8UC(n) ... CV_64FC(n) or CV_MAKETYPE(CV_8U, n) ... CV_MAKETYPE(CV_64F, n)等宏指令意指編譯時(shí)通道數(shù)大于4或者不明確

注意 CV_32FC1 == CV_32F, CV_32FC2 == CV_32FC(2) == CV_MAKETYPE(CV_32F, 2)以及CV_MAKETYPE(depth, n) == ((depth&7) + ((n-1)<<3)意味著常量類型是通過深度組成的沉眶,最低3位且通道數(shù)減1,下一個(gè)取log2(CV_CN_MAX)
例如:

Mat mtx(3, 3, CV_32F); //創(chuàng)建一個(gè)3x3的浮點(diǎn)矩陣
Mat cmtx(10, 1, CV_64FC2); //創(chuàng)建一個(gè)10x1的2通道浮點(diǎn)
                           //矩陣(10個(gè)元素的合成的迭代器)
Mat img(Size(1920, 1080), CV_8UC3); //創(chuàng)建一個(gè)3通道(彩色)圖片 
                                    //1920列1080行排苍。
Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); //創(chuàng)建一個(gè)單通道圖片,帶有相同的大小和相同的通道類型学密。

OpenCV不能構(gòu)建和處理更復(fù)雜的元素?cái)?shù)組淘衙。此外每個(gè)函數(shù)以及方法僅可以執(zhí)行所有數(shù)組類型中的一個(gè)類型,通常算法越復(fù)雜腻暮,格式可支持性越小彤守。
下面是一些格式使用范圍的例子:

  • 面部檢測(cè)算法僅支持8位的灰度或者色彩圖像
  • 線性代數(shù)算法和大多數(shù)的機(jī)器學(xué)習(xí)算法僅支持浮點(diǎn)數(shù)組毯侦。
  • 基礎(chǔ)函數(shù),例如cv::add具垫,支持所有類型侈离。
  • 色彩空間轉(zhuǎn)換函數(shù)支持8位、16位無符號(hào)類型和32位浮點(diǎn)類型筝蚕。
    每個(gè)函數(shù)支持的類型已經(jīng)根據(jù)實(shí)際需要定義好了卦碾,且可以在未來根據(jù)用戶的需求拓展。

輸入/輸出數(shù)組(InputArray and OutputArray)


許多OpenCV函數(shù)都能夠處理稠密二維或者多維數(shù)組起宽。這些函數(shù)通常都以cppMat作為參數(shù)洲胖,但在某些時(shí)候使用std::vector<>(比如存放點(diǎn)集)和cv::Matx(類似于3x3的單應(yīng)矩陣)顯得更為方便。為避免API的命名重復(fù)坯沪,特殊的“代理”類也被引入绿映。最基本的代理類就是cv::InputArray,其作用是將只讀數(shù)組作為函數(shù)輸入腐晾。派生自InputArray的類cv::OutputArray作為函數(shù)的輸出叉弦。通常不需要關(guān)注中間類型(不可聲明明確類型的變量)——它會(huì)自動(dòng)工作。故除了InputArray和OutputArray不能使用藻糖,總能使用的是 Mat, std::vector, cv::Matx<>, cv::Vec<>cv::Scalar淹冰。當(dāng)一個(gè)函數(shù)有可選的輸入和輸出數(shù)組,而你并沒有或者并不想輸入輸出颖御,傳遞cv::noArray()

錯(cuò)誤處理


OpenCV使用異常(Expection)來示意嚴(yán)重錯(cuò)誤榄棵。當(dāng)輸入數(shù)據(jù)類型正確且在規(guī)定的范圍之內(nèi),但是算法因?yàn)槟承┰驘o法運(yùn)作(比如優(yōu)化算法沒有收斂)時(shí)會(huì)返回一個(gè)特殊的錯(cuò)誤代碼(通常就是布爾值)潘拱。

異痴铞可以被cv::CV_Error(errcode, description)或者它的派生類實(shí)例化。反過來芦岂,cv::Exception也是std::Exception的派生類瘪弓。故其也可以很好的兼容標(biāo)準(zhǔn)C++庫中的代碼。

異常拋出通常是通過CV_Error(errcode, description)宏禽最、CV_Error(errcode, printf-spec,(打印參數(shù)))與打印類似的變量腺怯,或者是使用CV_Assert(condition)宏來檢查條件,并在不滿足條件時(shí)拋出異常川无。對(duì)于性能臨界的代碼呛占,CV_DbgAssert(condition)宏只在調(diào)試配置(Debug configuration)過程中保留。在自動(dòng)內(nèi)存管理情況下懦趋,如果突然發(fā)生錯(cuò)誤晾虑,所有內(nèi)部緩存會(huì)被自動(dòng)釋放。用戶只需要添加一個(gè)聲明即可捕獲異常:

try
 {
     ... // call OpenCV
}
catch( cv::Exception& e )
{
    const char* err_msg = e.what();
    std::cout << "exception caught: " << err_msg << std::endl;
 }

多線程和可重入性


當(dāng)前版本的OpenCV支持重入,也即是說同樣的函數(shù)或是不同類中的同樣方法可以被不同的線程調(diào)用帜篇。而且相同的Mat可以在不同線程中調(diào)用糙捺,因?yàn)橐糜?jì)數(shù)使用了特定體系結(jié)構(gòu)的原子指令(atomic instructions)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笙隙,一起剝皮案震驚了整個(gè)濱河市洪灯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竟痰,老刑警劉巖签钩,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異凯亮,居然都是意外死亡边臼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門假消,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柠并,“玉大人,你說我怎么就攤上這事富拗【视瑁” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵啃沪,是天一觀的道長(zhǎng)粘拾。 經(jīng)常有香客問我,道長(zhǎng)创千,這世上最難降的妖魔是什么缰雇? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮追驴,結(jié)果婚禮上械哟,老公的妹妹穿的比我還像新娘。我一直安慰自己殿雪,他們只是感情好暇咆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丙曙,像睡著了一般爸业。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亏镰,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天扯旷,我揣著相機(jī)與錄音,去河邊找鬼索抓。 笑死钧忽,一個(gè)胖子當(dāng)著我的面吹牛某抓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惰瓜,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼汉矿!你這毒婦竟也來了崎坊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤洲拇,失蹤者是張志新(化名)和其女友劉穎奈揍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赋续,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡男翰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纽乱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛾绎。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鸦列,靈堂內(nèi)的尸體忽然破棺而出租冠,到底是詐尸還是另有隱情,我是刑警寧澤薯嗤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布顽爹,位于F島的核電站,受9級(jí)特大地震影響骆姐,放射性物質(zhì)發(fā)生泄漏镜粤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一玻褪、第九天 我趴在偏房一處隱蔽的房頂上張望肉渴。 院中可真熱鬧,春花似錦归园、人聲如沸黄虱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捻浦。三九已至,卻和暖如春桥爽,著一層夾襖步出監(jiān)牢的瞬間朱灿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工钠四, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盗扒,地道東北人跪楞。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像侣灶,于是被迫代替她去往敵國(guó)和親甸祭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345