opencv C++常用算子封裝

簡介:封裝一些opencv C++的算子,達(dá)到一種開箱即用的效果敞映,在算法預(yù)研階段能快速出結(jié)果沸伏,可以當(dāng)做調(diào)用示例糕珊,也可直接使用避免每次都重復(fù)編寫。

在這里插入圖片描述

@[toc]

  • imageProcess.h

#pragma once
#include "opencv.hpp"

namespace cvbag
{
    bool isImageEmpty(const cv::Mat &image, const std::string functionName);

    int getAllImagePath( std::string folder, std::vector<cv::String> &imagePathList, bool flg=false);

    int showImage(const cv::Mat &image, const std::string winName = "img", const int waitKeyMode = 0, const int destroyMode = 0);

    int gaussBlur(const cv::Mat &image, cv::Mat &dst, const int ksize = 5, double sigma = 1.0);

    int sobel_x(const cv::Mat &image, cv::Mat &dst, const int ksize = 3);

    int sobel_y(const cv::Mat &image, cv::Mat &dst, const int ksize = 3);

    int sobel_xy(const cv::Mat &image, cv::Mat &dst, const int ksize = 3);

    int canny(const cv::Mat &image, cv::Mat &dst, const int low = 100, const int heigh = 200);

    int otsu(const cv::Mat &image, cv::Mat &dst);

    int threshold(const cv::Mat &image, cv::Mat &dst, const int th = 128, const int mode = 0, const int maxval = 255);

    int adaptiveThreshold(const cv::Mat &image, cv::Mat &dst, int blockSize = 11, double C = 15, double maxval = 255,
        int adaptiveMethod = cv::ADAPTIVE_THRESH_MEAN_C, int thresholdType = cv::THRESH_BINARY_INV);

    int  findContours(const cv::Mat &binaryImage, std::vector<std::vector<cv::Point>> &contours, int topologyMode = 1, int contoursType = 1);

    int drawContours(cv::Mat &image, const std::vector<std::vector<cv::Point>> &contours, int contoursIdx = -1, int b = 0, int g = 0, int r = 255);

    int dilate(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

    int erode(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

    int open(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

    int close(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize = 3, const int kernelMode = 0);

    //use the table to transform the pixels 
    int gammaTransform(const cv::Mat &image, cv::Mat &dst, const int  table[]);
    //if the input image's format  is 3 channels then use below method to transform the pixels
    int gammaTransform_threeChannels(const cv::Mat &image, cv::Mat &dst, const int table[]);
    //a[i] = int(pow(i / 255.0, gamma) *255.0);
    int getGammaTable(const double gamma, int *a, const int num = 256);
    //gamma API
    int gamma(const cv::Mat &image, cv::Mat &dst, const double gamma = 1.0);

    //gamma piecewise linear function transform
    int getGammaTable_piecewiseLinear(int *a, const int src1, const int dst1 , const int src2 , const int dst2 );
    //gamma_picewiseLinear 
    /*
        f(x) = (dst1 / src1) * x; if x<src1
          = [(dst2 - dst1) / (src2 - src1)] * (x - src1) + dst1; if x>=src1 and x<src2;
          = [(255 - dst2) / (255 - src2)] * (x - src2) + dst2; if x>=src2;
    */
    int gamma_picewiseLinear(const cv::Mat &image, cv::Mat &dst,
        const int src1 = 80, const int dst1 = 60, const int src2 = 160, const int dst2 = 180);
    
};
  • imageProcess.cpp

#include "imageProcess.h"

bool cvbag::isImageEmpty(const cv::Mat &image, const std::string functionName)
{
    if (image.empty())
    {
        std::cout << "ERROR \t in cvbag::"<<functionName<<" ,the input image is empty!\n";
        return true;
    }

    return false;
}

int cvbag::getAllImagePath(std::string folder, std::vector<cv::String> &imagePathList, bool flg)
{
    cv::glob(folder, imagePathList, flg);
    return 0;
}

int cvbag::showImage(const cv::Mat &image, const std::string winName, const int waitKeyMode, const int destroyMode)
{
    if (cvbag::isImageEmpty(image,"showImage"))
    {
        return - 1;
    }

    cv::namedWindow(winName, CV_WINDOW_NORMAL);
    cv::imshow(winName, image);
    cv::waitKey(waitKeyMode);
    if (destroyMode == 1)
    {
        cv::destroyWindow(winName);
    }

    return 0;
}

int cvbag::gaussBlur(const cv::Mat &image, cv::Mat &dst, const int ksize, double sigma)
{
    if (cvbag::isImageEmpty(image, "gaussBlur"))
    {
        return -1;
    }
    cv::GaussianBlur(image, dst, cv::Size(ksize, ksize), sigma);
    return 0;
}

int cvbag::sobel_x(const cv::Mat &image, cv::Mat &dst, const int ksize)
{
    if (cvbag::isImageEmpty(image, "sobel_x"))
    {
        return -1;
    }

    cv::Sobel(image, dst, CV_64F, 1, 0, ksize);
    return 0;
}

int cvbag::sobel_y(const cv::Mat &image, cv::Mat &dst, const int ksize)
{
    if (cvbag::isImageEmpty(image, "sobel_y"))
    {
        return -1;
    }

    cv::Sobel(image, dst, CV_64F, 0, 1, ksize);
    return 0;
}

int cvbag::sobel_xy(const cv::Mat &image, cv::Mat &dst, const int ksize)
{
    if (cvbag::isImageEmpty(image, "sobel_xy"))
    {
        return -1;
    }
    cv::Mat sobel_x, sobel_y;
    cvbag::sobel_x(image, sobel_x, ksize);
    cvbag::sobel_y(image, sobel_y, ksize);
    cv::addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0, dst);
    return 0;
}

int cvbag::canny(const cv::Mat &image, cv::Mat &dst, const int low, const int heigh)
{
    if (cvbag::isImageEmpty(image, "canny")) return -1;

    cv::Canny(image, dst, low, heigh);
    return 0;
}

int cvbag::otsu(const cv::Mat &image, cv::Mat &dst)
{
    if (cvbag::isImageEmpty(image, "adaptiveThreshold")) return -1;
    if (image.channels() == 3) cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
    cv::threshold(dst, dst, 0, 255, 8);
    return 0;
}

int cvbag::threshold(const cv::Mat &image, cv::Mat &dst, const int th , const int mode, const int maxval)
{
    /*
    enum ThresholdTypes {
    THRESH_BINARY     = 0, //!< \f[\texttt{dst} (x,y) =  \fork{\texttt{maxval}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
    THRESH_BINARY_INV = 1, //!< \f[\texttt{dst} (x,y) =  \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{maxval}}{otherwise}\f]
    THRESH_TRUNC      = 2, //!< \f[\texttt{dst} (x,y) =  \fork{\texttt{threshold}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
    THRESH_TOZERO     = 3, //!< \f[\texttt{dst} (x,y) =  \fork{\texttt{src}(x,y)}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
    THRESH_TOZERO_INV = 4, //!< \f[\texttt{dst} (x,y) =  \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
    THRESH_MASK       = 7,
    THRESH_OTSU       = 8, //!< flag, use Otsu algorithm to choose the optimal threshold value
    THRESH_TRIANGLE   = 16 //!< flag, use Triangle algorithm to choose the optimal threshold value
};
    */

    if (cvbag::isImageEmpty(image, "adaptiveThreshold")) return -1;
    if (image.channels() == 3) cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
    cv::threshold(dst, dst, th, maxval, mode);

    return 0;
}

int cvbag::adaptiveThreshold(const cv::Mat &image, cv::Mat &dst, int blockSize, double C, double maxval,
    int adaptiveMethod, int thresholdType)
{
    if (cvbag::isImageEmpty(image, "adaptiveThreshold")) return -1;
    //blockSize must be an odd number,like 3,5,7...
    if (blockSize % 2 == 0) blockSize += 1;
    if (image.channels() == 3) {
        cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
        cv::adaptiveThreshold(dst, dst, maxval, adaptiveMethod, thresholdType, blockSize, C);
    } 
    else {
        cv::adaptiveThreshold(image, dst, maxval, adaptiveMethod, thresholdType, blockSize, C);
    }

    
    return 0;
}

int  cvbag::findContours(const cv::Mat &binaryImage, std::vector<std::vector<cv::Point>> &contours,     int topologyMode , int contoursType )
{
    /** Contour retrieval modes */
    /*enum
    {
        CV_RETR_EXTERNAL = 0,
        CV_RETR_LIST = 1,
        CV_RETR_CCOMP = 2,
        CV_RETR_TREE = 3,
        CV_RETR_FLOODFILL = 4
    };*/

    /** Contour approximation methods */
    /*enum
    {
        CV_CHAIN_CODE = 0,
        CV_CHAIN_APPROX_NONE = 1,
        CV_CHAIN_APPROX_SIMPLE = 2,
        CV_CHAIN_APPROX_TC89_L1 = 3,
        CV_CHAIN_APPROX_TC89_KCOS = 4,
        CV_LINK_RUNS = 5
    };*/

    if (cvbag::isImageEmpty(binaryImage, "findContours")) return -1;

    std::vector<cv::Vec4i> hierarchy;
    if (binaryImage.channels() == 3) return -1;
    cv::findContours(binaryImage, contours, topologyMode, contoursType);

    return 0;
}

int cvbag::drawContours(cv::Mat &image, const std::vector<std::vector<cv::Point>> &contours,    int contoursIdx , int b , int g , int r )
{
    if (cvbag::isImageEmpty(image, "drawContours")) return -1;
    cv::drawContours(image, contours, contoursIdx, cv::Scalar(b, g, r));
    return 0;
}

int cvbag::dilate(const cv::Mat &binaryImage, cv::Mat &dst, const  int ksize , const int kernelMode )
{
    /*  MORPH_ERODE
        MORPH_DILATE
        MORPH_OPEN      dst = open(src, element) = dilate(erode(src, element))
        MORPH_CLOSE     dst = close(src, element) = erode(dilate(src, element))
        MORPH_GRADIENT      dst = morph_grad(src, element) = dilate(src, element)?erode(src, element)
        MORPH_TOPHAT        dst = tophat(src, element) = src?open(src, element)
        MORPH_BLACKHAT      dst = blackhat(src, element) = close(src, element)?src
        MORPH_HITMISS
        "hit or miss" . - Only supported for CV_8UC1 binary images.
        A tutorial canbe found in the documentation
    */

    /*
    enum MorphTypes{
    MORPH_ERODE    = 0,
    MORPH_DILATE   = 1,
    MORPH_OPEN     = 2,
    MORPH_CLOSE    = 3,
    MORPH_GRADIENT = 4,
    MORPH_TOPHAT   = 5,
    MORPH_BLACKHAT = 6,
    MORPH_HITMISS  = 7
     };
    */
    /*
    enum MorphShapes {
    MORPH_RECT    = 0, //!< a rectangular structuring element:  \f[E_{ij}=1\f]
    MORPH_CROSS   = 1, //!< a cross-shaped structuring element:
                       //!< \f[E_{ij} =  \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}\f]
    MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed
                      //!< into the rectangle Rect(0, 0, esize.width, 0.esize.height)
    };
    */
    if (cvbag::isImageEmpty(binaryImage, "dilate")) return -1;
    if (binaryImage.channels() == 3) return -1;
    cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
    cv::morphologyEx(binaryImage, dst, 1, element);
    return 0;
}

int cvbag::erode(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize , const int kernelMode )
{
    /*  MORPH_ERODE
        MORPH_DILATE
        MORPH_OPEN      dst = open(src, element) = dilate(erode(src, element))
        MORPH_CLOSE     dst = close(src, element) = erode(dilate(src, element))
        MORPH_GRADIENT      dst = morph_grad(src, element) = dilate(src, element)?erode(src, element)
        MORPH_TOPHAT        dst = tophat(src, element) = src?open(src, element)
        MORPH_BLACKHAT      dst = blackhat(src, element) = close(src, element)?src
        MORPH_HITMISS
        "hit or miss" . - Only supported for CV_8UC1 binary images.
        A tutorial canbe found in the documentation
    */

    /*
    enum MorphTypes{
    MORPH_ERODE    = 0,
    MORPH_DILATE   = 1,
    MORPH_OPEN     = 2,
    MORPH_CLOSE    = 3,
    MORPH_GRADIENT = 4,
    MORPH_TOPHAT   = 5,
    MORPH_BLACKHAT = 6,
    MORPH_HITMISS  = 7
     };
    */
    /*
    enum MorphShapes {
    MORPH_RECT    = 0, //!< a rectangular structuring element:  \f[E_{ij}=1\f]
    MORPH_CROSS   = 1, //!< a cross-shaped structuring element:
                       //!< \f[E_{ij} =  \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}\f]
    MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed
                      //!< into the rectangle Rect(0, 0, esize.width, 0.esize.height)
    };
    */
    if (cvbag::isImageEmpty(binaryImage, "erode")) return -1;
    if ( binaryImage.channels() == 3) return -1;
    cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
    cv::morphologyEx(binaryImage, dst, 0, element);
    return 0;
}

int cvbag::open(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize, const int kernelMode)
{
    
    if (cvbag::isImageEmpty(binaryImage, "erode")) return -1;
    if (binaryImage.channels() == 3) return -1;
    cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
    cv::morphologyEx(binaryImage, dst, 2, element);
    return 0;
}

int cvbag::close(const cv::Mat &binaryImage, cv::Mat &dst, const int ksize, const int kernelMode)
{

    if (cvbag::isImageEmpty(binaryImage, "erode")) return -1;
    if (binaryImage.channels() == 3) return -1;
    cv::Mat element = cv::getStructuringElement(kernelMode, cv::Size(ksize, ksize));
    cv::morphologyEx(binaryImage, dst, 3, element);
    return 0;
}

int cvbag::gammaTransform_threeChannels(const cv::Mat &image, cv::Mat &dst, const int table[])
{
    std::vector<cv::Mat> channelsImage;
    std::vector<cv::Mat> channelsImage_dst;
    cv::split(image, channelsImage);
    for (int i = 0; i < channelsImage.size(); i++)
    {
        channelsImage_dst.push_back(cv::Mat::zeros(cv::Size(image.cols, image.rows), CV_8UC1));

    }

    for (int i = 0; i < channelsImage.size(); i++)
    {
        gammaTransform(channelsImage[i], channelsImage_dst[i], table);
    }
    cv::merge(channelsImage_dst, dst);

    return 0;
}

int cvbag::getGammaTable(const double gamma, int *a, const int num )
{
    for (int i = 0; i < num; i++)
    {
        a[i] = int(pow(i / 255.0, gamma) *255.0);
    }

    return 0;
}

int cvbag::gamma(const cv::Mat &image, cv::Mat &dst, const double gamma )
{
    if (image.empty()) return -1;

    int table[256] = { 0 };
    getGammaTable(gamma, table);

    gammaTransform(image, dst, table);


    return 0;
}

int cvbag::gammaTransform(const cv::Mat &image, cv::Mat &dst, const int  table[])
{
    if (image.empty()) return -1;

    if (image.channels() == 3)
    {
        gammaTransform_threeChannels(image, dst, table);
    }

    if (dst.empty()) dst = cv::Mat::zeros(cv::Size(image.cols, image.rows), CV_8UC1);

    const uchar * ps = NULL;
    uchar * pd = NULL;

    for (int i = 0; i < image.rows; i++)
    {
        ps = image.ptr<uchar>(i);
        pd = dst.ptr<uchar>(i);
        for (int j = 0; j < image.cols; j++)
        {
            *(pd + j) = table[int(*(ps + j))];
        }
    }
    return 0;
}

int cvbag::gamma_picewiseLinear(const cv::Mat &image, cv::Mat &dst, const int src1, const int dst1, const int src2, const int dst2)
{
    if (image.empty()) return -1;

    int table[256] = { 0 };
    if (src1<=0 | src1 > 255 | src1>=src2 | src2 > 255 | dst1<0 | dst1 > 255 | dst2<0 | dst2 > 255) return -1;

    getGammaTable_piecewiseLinear(table,src1,dst1,src2,dst2);

    gammaTransform(image, dst, table);

    return 0;
}

int cvbag::getGammaTable_piecewiseLinear(int *a, const int src1 , const int dst1 , const int src2 , const int dst2 )
{
    for (int i = 0; i < src1; i++)
    {
        a[i] = int(float(dst1) / float(src1)*i);
    }

    for (int i = src1; i < src2; i++)
    {
        a[i] = int(float(dst2 - dst1) / float(src2 - src1) * (i - src1) + dst1);
    }

    for (int i = src2; i < 256; i++)
    {
        a[i] = int(float(255 - dst2) / float(255 - src2) * (i - src2) + dst2);
    }

    return 0;
}


int demo()
{
    //const std::string fileName = "K:\\imageData\\golden_pad\\204.bmp";
    const std::string fileName = "K:\\imageData\\lena\\Lena.png";

    //cvbag tool;

    //showImage
    cv::Mat image = cv::imread(fileName);
    cvbag::showImage(image, "image",0,0);

    //gauss smooth
    cv::Mat gauss;
    cvbag::gaussBlur(image, gauss);
    cvbag::showImage(gauss, "gauss");

    //sobel edge detect
    cv::Mat sobel_xy;
    cvbag::sobel_x(gauss, sobel_xy);
    ////convert format CV_64F to CV_8U ,so that the image can use cv::imshow to show image.
    cv::convertScaleAbs(sobel_xy, sobel_xy);
    cvbag::showImage(sobel_xy, "sobel_xy");

    //otsu
    cv::Mat otsu;
    cvbag::otsu(gauss, otsu);
    cvbag::showImage(otsu, "otsu");

    //threshold
    cv::Mat threshold;
    cvbag::threshold(gauss, threshold, 120,8+1);
    cvbag::showImage(threshold, "threshold");

    //adaptiveThreshold
    cv::Mat adaptiveThreshold;
    cvbag::adaptiveThreshold(gauss, adaptiveThreshold,11,8 );
    cvbag::showImage(adaptiveThreshold, "adaptiveThreshold");

    //canny
    cv::Mat canny;
    cvbag::canny(image, canny, 120, 180);
    cvbag::showImage(canny, "canny");

    //contours
    std::vector<std::vector<cv::Point>> contours;
    cvbag::findContours(adaptiveThreshold, contours);
    cv::Mat conImage = gauss.clone();
    cvbag::drawContours(conImage, contours, -1, 0, 255, 0);
    cvbag::showImage(conImage, "contours");

    //dilate
    cv::Mat dilate;
    cvbag::dilate(otsu, dilate, 3, 0);
    cvbag::showImage(dilate, "dilate");

    //erode
    cv::Mat erode;
    cvbag::erode(otsu, erode, 3, 0);
    cvbag::showImage(erode, "erode");

    //open
    cv::Mat open;
    cvbag::open(otsu, open);
    cvbag::showImage(open, "open");

    //close
    cv::Mat close;
    cvbag::close(otsu, close);
    cvbag::showImage(close, "close");

    //gamma
    cv::Mat gamma;
    cvbag::gamma(image, gamma, 2);
    cvbag::showImage(gamma, "gamma");

    //gamma_piecewiseLinaer
    cv::Mat gamma_piece;
    cvbag::gamma_picewiseLinear(image, gamma_piece, 120, 60, 160, 200);
    cvbag::showImage(gamma_piece, "gamma_piece");

    return 0;
}



int main()
{
    demo();
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毅糟,一起剝皮案震驚了整個濱河市红选,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姆另,老刑警劉巖喇肋,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異迹辐,居然都是意外死亡蝶防,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門明吩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來间学,“玉大人,你說我怎么就攤上這事印荔〉秃” “怎么了?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵仍律,是天一觀的道長嘿悬。 經(jīng)常有香客問我,道長染苛,這世上最難降的妖魔是什么鹊漠? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮茶行,結(jié)果婚禮上躯概,老公的妹妹穿的比我還像新娘。我一直安慰自己畔师,他們只是感情好娶靡,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著看锉,像睡著了一般姿锭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伯铣,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天呻此,我揣著相機(jī)與錄音,去河邊找鬼腔寡。 笑死焚鲜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忿磅,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼糯彬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了葱她?” 一聲冷哼從身側(cè)響起撩扒,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吨些,沒想到半個月后搓谆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锤灿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年挽拔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片但校。...
    茶點(diǎn)故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡螃诅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出状囱,到底是詐尸還是另有隱情术裸,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布亭枷,位于F島的核電站袭艺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叨粘。R本人自食惡果不足惜猾编,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望升敲。 院中可真熱鬧答倡,春花似錦、人聲如沸驴党。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽港庄。三九已至倔既,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹏氧,已是汗流浹背渤涌。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留把还,地道東北人实蓬。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓稿存,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瞳秽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評論 2 361

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