iOS Core ML與Vision初識(shí)

教之道 貴以專 昔孟母 擇鄰處 子不學(xué) 斷機(jī)杼

隨著蘋果新品iPhone x的發(fā)布,正式版iOS 11也就馬上要推送過(guò)來(lái)了辽旋,在正式版本到來(lái)之前比較好奇协怒,于是就去下載了個(gè)Beat版本刷了下奕删,感覺(jué)還不錯(cuò)奕坟。WWDC 2017推出了機(jī)器學(xué)習(xí)框架和ARKit兩個(gè)比較有意思的東西,本想先來(lái)學(xué)習(xí)學(xué)習(xí)AR罗侯,無(wú)奈手機(jī)剛好不在版本中.....真受傷器腋,只好來(lái)學(xué)習(xí)學(xué)習(xí)機(jī)器學(xué)習(xí)了,下面進(jìn)入正題吧钩杰。

先看看大概效果吧

coreml1.gif
什么是機(jī)器學(xué)習(xí)纫塌?

Core ML出現(xiàn)之前,機(jī)器學(xué)習(xí)應(yīng)該還是比較難學(xué)的讲弄,然而這一出現(xiàn)措左,直接大大降低了學(xué)習(xí)的門檻,可見蘋果在這方面花的精力還是不少避除。那么機(jī)器學(xué)習(xí)到底是什么呢怎披?簡(jiǎn)單來(lái)說(shuō),就是用大量的數(shù)據(jù)去采集物體的特性特征瓶摆,將其裝入模型凉逛,當(dāng)我們用的時(shí)候,可以通過(guò)查詢模型群井,來(lái)快速區(qū)別出當(dāng)前物體屬于什么類鱼炒,有什么特性等等。而Core ML實(shí)際做的事情就是使用事先訓(xùn)練好的模型,在使用時(shí)昔瞧,對(duì)相關(guān)模塊進(jìn)行預(yù)測(cè),最終返回結(jié)果菩佑,這種在本地進(jìn)行預(yù)測(cè)的方式可以不依賴網(wǎng)絡(luò)自晰,也可以降低處理時(shí)間∩耘鳎可以這么說(shuō)酬荞,Core ML 讓我們更容易在 App中使用訓(xùn)練過(guò)的模型,而Vision讓我們輕松訪問(wèn)蘋果的模型瞧哟,用于面部檢測(cè)混巧、面部特征點(diǎn)、文字勤揩、矩形咧党、條形碼和物體。

Core ML 和 Vision使用

在使用之前陨亡,你必須要保證你的環(huán)境是在xcode 9.0 + iOS 11傍衡,然后你可以去官網(wǎng)下載Core ML模型,目前已經(jīng)有6種模型了负蠕,分別如下

1.png
2.png
3.png
4.png

從其介紹我們可以看出分別的功能
MobileNet:大意是從一組1000個(gè)類別中檢測(cè)出圖像中的占主導(dǎo)地位的物體蛙埂,如樹、動(dòng)物遮糖、食物绣的、車輛、人等等欲账。
SqueezeNet:同上
Places205-GoogLeNet:大意是從205個(gè)類別中檢測(cè)到圖像的場(chǎng)景屡江,如機(jī)場(chǎng)終端、臥室敬惦、森林盼理、海岸等。
ResNet50:大意是從一組1000個(gè)類別中檢測(cè)出圖像中的占主導(dǎo)地位的物體俄删,如樹宏怔、動(dòng)物、食物畴椰、車輛臊诊、人等等
Inception v3:同上
VGG16:同上

當(dāng)然這都是蘋果提供的模型,如果你有自己的模型的話斜脂,可以通過(guò)工具將其轉(zhuǎn)換抓艳,參考文檔
在了解上面的模型功能后,我們可以選擇性的對(duì)其進(jìn)行下載帚戳,目前我這里下載了四種模型

model.png

將下載好的模型玷或,直接拖入工程中儡首,這里需要注意的問(wèn)題是,需要檢查下

check.png

這個(gè)位置是否有該模型偏友,我不知道是不是我這個(gè)xcode版本的bug蔬胯,當(dāng)我拖入的時(shí)候,后面并沒(méi)有位他,這個(gè)時(shí)候就需要手動(dòng)進(jìn)行添加一次氛濒,在這之后,我們還需要檢查下模型類是否生成鹅髓,點(diǎn)擊你需要用的模型舞竿,然后查看下面位置是否有箭頭

modelOk.png

當(dāng)這個(gè)位置箭頭生成好后,我們就可以進(jìn)行代碼的編寫了

代碼部分

在寫代碼之前窿冯,我們還需要了解一些東西骗奖,那就是模型生成的類中都有什么方法,這里我們就以Resnet50為類靡菇,在ViewController中導(dǎo)入頭文件#import "Resnet50.h"重归,當(dāng)我們?cè)谳斎?code>Res的時(shí)候,就會(huì)自動(dòng)補(bǔ)全厦凤,導(dǎo)入其它模型的時(shí)候鼻吮,也可以這么來(lái)模仿。在進(jìn)入Resnet50頭文件中较鼓,我們可以看到其中分為三個(gè)類椎木,分別為:Resnet50InputResnet50Output博烂、Resnet50香椎,看其意思也能猜到,分別為輸入禽篱、輸出畜伐、和主要使用類。
Resnet50中躺率,我們可以看到三個(gè)方法玛界,分別如下:

- (nullable instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError * _Nullable * _Nullable)error;

/**
    Make a prediction using the standard interface
    @param input an instance of Resnet50Input to predict from
    @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
    @return the prediction as Resnet50Output
*/
- (nullable Resnet50Output *)predictionFromFeatures:(Resnet50Input *)input error:(NSError * _Nullable * _Nullable)error;

/**
    Make a prediction using the convenience interface
    @param image Input image of scene to be classified as color (kCVPixelFormatType_32BGRA) image buffer, 224 pixels wide by 224 pixels high:
    @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
    @return the prediction as Resnet50Output
*/
- (nullable Resnet50Output *)predictionFromImage:(CVPixelBufferRef)image error:(NSError * _Nullable * _Nullable)error;

第一個(gè)應(yīng)該是初始化方法,后面兩個(gè)應(yīng)該是輸出對(duì)象的方法悼吱,看到這里慎框,不由的馬上開始動(dòng)手了。都說(shuō)心急吃不了熱豆腐后添,果然是這樣笨枯,后面遇到一堆堆坑,容我慢慢道來(lái)。

一開始我的初始化方法是這樣的

    Resnet50* resnet50 = [[Resnet50 alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Resnet50" ofType:@"mlmodel"]] error:nil];

咋一看馅精,恩严嗜,應(yīng)該是相當(dāng)?shù)?code>perfect,然而現(xiàn)實(shí)是殘酷的洲敢,出意外的崩潰了...
日志如下

 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'

為了找準(zhǔn)位置阻问,我決定打個(gè)全局?jǐn)帱c(diǎn),信心倍增的開始下一次運(yùn)行沦疾,然而還是一樣的效果,氣的我第队,果斷直接只寫了下面的初始化方法

Resnet50* resnet50 = [[Resnet50 alloc] init];

這次沒(méi)有崩潰哮塞,而是直接進(jìn)入了下面的圖

bb.png

偶然的機(jī)會(huì),見識(shí)到了Resnet50內(nèi)部的實(shí)現(xiàn)方法凳谦,首先映入眼簾的是mlmodelc這個(gè)類型....想必大家也明白了吧忆畅!但是咋就進(jìn)入了這個(gè)地方了?幸運(yùn)的是讓斷點(diǎn)繼續(xù)執(zhí)行兩次就ok了尸执,于是我大膽猜想家凯,是不是斷點(diǎn)引起的,馬上取消斷點(diǎn)如失,重新Run绊诲,耶,果然正確褪贵,一切順利進(jìn)行中...此時(shí)的我是淚崩的掂之。
這一系列經(jīng)過(guò)說(shuō)明:
1、模型的后綴為mlmodelc
2脆丁、調(diào)試的時(shí)候可以取消斷點(diǎn)世舰,方便調(diào)試,省的點(diǎn)來(lái)點(diǎn)去槽卫,當(dāng)然如果想看看內(nèi)部實(shí)現(xiàn)跟压,可以加上斷點(diǎn)

在這里調(diào)通后,就是下一步輸出的問(wèn)題了歼培,上面也看到了有兩個(gè)方法震蒋,一個(gè)是根據(jù)Resnet50Input一個(gè)是根據(jù)CVPixelBufferRef,而在Resnet50Input中又有這么一個(gè)初始化方法

- (instancetype)initWithImage:(CVPixelBufferRef)image;

看來(lái)這個(gè)CVPixelBufferRef是必不可少的了
關(guān)于這個(gè)丐怯,我在網(wǎng)上找了一個(gè)方法喷好,方法如下

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image{
    
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    
    CVPixelBufferRef pxbuffer = NULL;
    
    CGFloat frameWidth = CGImageGetWidth(image);
    CGFloat frameHeight = CGImageGetHeight(image);
    
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
                                          frameWidth,
                                          frameHeight,
                                          kCVPixelFormatType_32ARGB,
                                          (__bridge CFDictionaryRef) options,
                                          &pxbuffer);
    
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
    
    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);
    
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGContextRef context = CGBitmapContextCreate(pxdata,
                                                 frameWidth,
                                                 frameHeight,
                                                 8,
                                                 CVPixelBufferGetBytesPerRow(pxbuffer),
                                                 rgbColorSpace,
                                                 (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
    NSParameterAssert(context);
    CGContextConcatCTM(context, CGAffineTransformIdentity);
    CGContextDrawImage(context, CGRectMake(0,
                                           0,
                                           frameWidth,
                                           frameHeight),
                       image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
    
    return pxbuffer;
}

在這個(gè)方法寫完之后,我將之前的方法進(jìn)行了完善读跷,得到下面的代碼

- (NSString*)predictionWithResnet50:(CVPixelBufferRef )buffer
{
    Resnet50* resnet50 = [[Resnet50 alloc] init];
    
    NSError *predictionError = nil;
    Resnet50Output *resnet50Output = [resnet50 predictionFromImage:buffer error:&predictionError];
    if (predictionError) {
        return predictionError.description;
    } else {
        return [NSString stringWithFormat:@"識(shí)別結(jié)果:%@,匹配率:%.2f",resnet50Output.classLabel, [[resnet50Output.classLabelProbs valueForKey:resnet50Output.classLabel]floatValue]];
    }
}

懷著激動(dòng)的心情梗搅,添加了imageviewlable,和下面的代碼

    CGImageRef cgImageRef = [imageview.image CGImage];
    lable.text = [self predictionWithResnet50:[self pixelBufferFromCGImage:cgImageRef]];

Run...

error1.png
error.png

看到這個(gè)結(jié)果,失落的半天不想說(shuō)話无切,幸好有日志荡短,仔細(xì)看日志,你會(huì)發(fā)現(xiàn)哆键,好像是圖片的大小不對(duì)...提示說(shuō)是要224掘托,好吧,那就改改尺寸看看

- (UIImage *)scaleToSize:(CGSize)size image:(UIImage *)image {
    UIGraphicsBeginImageContext(size);
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}
    UIImage *scaledImage = [self scaleToSize:CGSizeMake(224, 224) image:imageview.image];
    CGImageRef cgImageRef = [scaledImage CGImage];
    lable.text = [self predictionWithResnet50:[self pixelBufferFromCGImage:cgImageRef]];

Run...

success.png

終于成功了!!!籍嘹,至于結(jié)果嘛闪盔,還可以算滿意,畢竟狼王加內(nèi)特就是打籃球的 辱士,哈哈泪掀。

后面我又嘗試了其它類,我原以為尺寸都是224颂碘,然而在Inceptionv3的時(shí)候异赫,提示我是要用229,于是我就仔細(xì)查看了下類代碼头岔,發(fā)現(xiàn)其中已經(jīng)有這方面的說(shuō)明....

/// Input image to be classified as color (kCVPixelFormatType_32BGRA) image buffer, 299 pixels wide by 299 pixels high

/// Input image of scene to be classified as color (kCVPixelFormatType_32BGRA) image buffer, 224 pixels wide by 224 pixels high

到此突然想到塔拳,在上面,我們查看模型的圖中峡竣,也有說(shuō)明靠抑,就是inputs相關(guān)參數(shù)那列。
到這里澎胡,好像我們還有一個(gè)類沒(méi)有用到孕荠,那就是Vision,那么通過(guò)Vision又怎么和Core ML來(lái)一起實(shí)現(xiàn)呢攻谁?

Vision使用
@interface VNCoreMLModel : NSObject

- (instancetype) init  NS_UNAVAILABLE;

/*!
    @brief Create a model container to be used with VNCoreMLRequest based on a Core ML model. This can fail if the model is not supported. Examples for a model that is not supported is a model that does not take an image as any of its inputs.
 
    @param model    The MLModel from CoreML to be used.
    
    @param  error   Returns the error code and description, if the model is not supported.
 */

+ (nullable instancetype) modelForMLModel:(MLModel*)model error:(NSError**)error;

@end

在上面VNCoreMLModel類中稚伍,我們可以看到其初始化方法之一一個(gè)modelForMLModel,而init是無(wú)效的戚宦,在modelForMLModel中个曙,有MLModel這么一個(gè)對(duì)象的參數(shù),而在Core ML模型類中受楼,我們也發(fā)現(xiàn)有這么一個(gè)屬性垦搬,看來(lái)我們可以通過(guò)這個(gè)關(guān)系將其聯(lián)系起來(lái)。

@interface Resnet50 : NSObject
@property (readonly, nonatomic, nullable) MLModel * model;

在當(dāng)前類繼續(xù)往下翻艳汽,就能看到類VNCoreMLRequest

@interface VNCoreMLRequest : VNImageBasedRequest

/*!
 @brief The model from CoreML wrapped in a VNCoreMLModel.
 */
@property (readonly, nonatomic, nonnull) VNCoreMLModel *model;

@property (nonatomic)VNImageCropAndScaleOption imageCropAndScaleOption;


/*!
    @brief Create a new request with a model.
 
    @param model        The VNCoreMLModel to be used.
 */
- (instancetype) initWithModel:(VNCoreMLModel *)model;

/*!
    @brief Create a new request with a model.
 
    @param model        The VNCoreMLModel to be used.
    
    @param  completionHandler   The block that is invoked when the request has been performed.
 */
- (instancetype) initWithModel:(VNCoreMLModel *)model completionHandler:(nullable VNRequestCompletionHandler)completionHandler NS_DESIGNATED_INITIALIZER;


- (instancetype) init  NS_UNAVAILABLE;
- (instancetype) initWithCompletionHandler:(nullable VNRequestCompletionHandler)completionHandler NS_UNAVAILABLE;

@end

在其中猴贰,我們看到方法initWithModelVNCoreMLModel類相關(guān)聯(lián),于是就有了下面的代碼

- (void)predictionWithResnet50WithImage:(CIImage * )image
{
    //兩種初始化方法均可
//    Resnet50* resnet50 = [[Resnet50 alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Resnet50" ofType:@"mlmodelc"]] error:nil];
    
    Resnet50* resnet50 = [[Resnet50 alloc] init];
    NSError *error = nil;
    //創(chuàng)建VNCoreMLModel
    VNCoreMLModel *vnCoreMMModel = [VNCoreMLModel modelForMLModel:resnet50.model error:&error];
    
    // 創(chuàng)建request
    VNCoreMLRequest *request = [[VNCoreMLRequest alloc] initWithModel:vnCoreMMModel completionHandler:^(VNRequest * _Nonnull request, NSError * _Nullable error) {

    }];
}

到這里河狐,好像還差點(diǎn)什么米绕,是的瑟捣,貌似我們的圖片沒(méi)有關(guān)聯(lián)上來(lái),只好去查找資料栅干,最后發(fā)現(xiàn)一個(gè)最重要的類迈套,那就是VNImageRequestHandler,在這個(gè)類中碱鳞,我還發(fā)現(xiàn)一個(gè)非常重要的方法

- (BOOL)performRequests:(NSArray<VNRequest *> *)requests error:(NSError **)error;

瞬間就將VNCoreMLRequest類關(guān)聯(lián)起來(lái)了桑李,因?yàn)?code>VNCoreMLRequest最終還是繼承VNRequest,在相關(guān)文檔的幫助下窿给,最終有了下面的代碼

- (void)predictionWithResnet50WithImage:(CIImage * )image
{
    //兩種初始化方法均可
//    Resnet50* resnet50 = [[Resnet50 alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Resnet50" ofType:@"mlmodelc"]] error:nil];
    
    Resnet50* resnet50 = [[Resnet50 alloc] init];
    NSError *error = nil;
    //創(chuàng)建VNCoreMLModel
    VNCoreMLModel *vnCoreMMModel = [VNCoreMLModel modelForMLModel:resnet50.model error:&error];
    
    // 創(chuàng)建處理requestHandler
    VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithCIImage:image options:@{}];
    
    NSLog(@" 打印信息:%@",handler);
    // 創(chuàng)建request
    VNCoreMLRequest *request = [[VNCoreMLRequest alloc] initWithModel:vnCoreMMModel completionHandler:^(VNRequest * _Nonnull request, NSError * _Nullable error) {

        CGFloat confidence = 0.0f;
        
        VNClassificationObservation *tempClassification = nil;
        
        for (VNClassificationObservation *classification in request.results) {
            if (classification.confidence > confidence) {
                confidence = classification.confidence;
                tempClassification = classification;
            }
        }
        self.descriptionLable.text = [NSString stringWithFormat:@"識(shí)別結(jié)果:%@,匹配率:%.2f",tempClassification.identifier,tempClassification.confidence];
    }];
    
    // 發(fā)送識(shí)別請(qǐng)求
    [handler performRequests:@[request] error:&error];
    if (error) {
        NSLog(@"%@",error.localizedDescription);
    }
}

通過(guò)這個(gè)方法贵白,我們就可以不用再去考慮圖片的大小了,所有的處理和查詢Vision已經(jīng)幫我們解決了崩泡。
到這里為止戒洼,還有幾個(gè)疑問(wèn)

- (instancetype)initWithCIImage:(CIImage *)image options:(NSDictionary<VNImageOption, id> *)options;


/*!
 @brief initWithCIImage:options:orientation creates a VNImageRequestHandler to be used for performing requests against the image passed in as a CIImage.
 
 @param image A CIImage containing the image to be used for performing the requests. The content of the image cannot be modified.
 @param orientation The orientation of the image/buffer based on the EXIF specification. For details see kCGImagePropertyOrientation. The value has to be an integer from 1 to 8. This superceeds every other orientation information.
 @param options A dictionary with options specifying auxilary information for the buffer/image like VNImageOptionCameraIntrinsics

 
 @note:  Request results may not be accurate in simulator due to CI's inability to render certain pixel formats in the simulator
 */
- (instancetype)initWithCIImage:(CIImage *)image orientation:(CGImagePropertyOrientation)orientation options:(NSDictionary<VNImageOption, id> *)options;

就是在VNImageRequestHandler還有許多初始化函數(shù),而且還有些參數(shù)允华,暫時(shí)還沒(méi)去研究,后續(xù)研究好了寥掐,再來(lái)補(bǔ)充靴寂。

下面還是奉上demo,有什么錯(cuò)誤召耘,還望各位多多指教百炬。

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市污它,隨后出現(xiàn)的幾起案子剖踊,更是在濱河造成了極大的恐慌,老刑警劉巖衫贬,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件德澈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡固惯,警方通過(guò)查閱死者的電腦和手機(jī)梆造,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)葬毫,“玉大人镇辉,你說(shuō)我怎么就攤上這事√瘢” “怎么了忽肛?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)烂斋。 經(jīng)常有香客問(wèn)我屹逛,道長(zhǎng)础废,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任煎源,我火速辦了婚禮色迂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘手销。我一直安慰自己歇僧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布锋拖。 她就那樣靜靜地躺著诈悍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兽埃。 梳的紋絲不亂的頭發(fā)上侥钳,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音柄错,去河邊找鬼舷夺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛售貌,可吹牛的內(nèi)容都是我干的给猾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼颂跨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼敢伸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起恒削,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤池颈,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后钓丰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躯砰,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年携丁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弃揽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡则北,死狀恐怖矿微,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尚揣,我是刑警寧澤涌矢,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站快骗,受9級(jí)特大地震影響娜庇,放射性物質(zhì)發(fā)生泄漏塔次。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一名秀、第九天 我趴在偏房一處隱蔽的房頂上張望励负。 院中可真熱鬧,春花似錦匕得、人聲如沸继榆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)略吨。三九已至,卻和暖如春考阱,著一層夾襖步出監(jiān)牢的瞬間翠忠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工乞榨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秽之,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓吃既,卻偏偏與公主長(zhǎng)得像政溃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子态秧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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