OpenCV -Android Studio 中使用(opencv-3.4.0-android-sdk)

源碼:https://github.com/huangshuyuan/OpenCvDemo-Master/

一、導入程序

1. 確定SdkVersion

在導入程序之前阻问,我們需要先確定待會的OpenCv工程中的一些和SdkVersion有關的配置,最好的辦法就是先用AS建一個HelloWorld握童,也可以順便熟悉一下Android Studio的開發(fā)流程罪佳。在工程中打開build.gradle痢畜,可以得到我們需要的信息:

這個隨意,和開發(fā)的APP的兼容性有關`
  compileSdkVersion 26
    buildToolsVersion "26.0.2"

    defaultConfig {
        applicationId "org.opencv.samples.facedetect"
        minSdkVersion 14
        targetSdkVersion 26

        ndk {
            moduleName "detection_based_tracker"
            abiFilters "armeabi-v7a"
        }
    }

2.導入samples\face-detection

第一步:



第二步:


找到opencv下載的demo


打開肺稀,直接下一步就行第股,我這邊已經(jīng)導入過了


此時,我們在AS左側(cè)的Project窗口的打開如下的配置文件:
openCVSamplefacedetection->src->build.gradle

修改如下4個配置信息:

compileSdkVersion 26
buildToolsVersion 26.0.2
minSdkVersion 14
targetSdkVersion  26

在修改完成之后话原,需要重新進行”Gradle project sync”夕吻,點擊Tools->Android->Sync Project with Gradle Files:

image.png

原因在于,工程openCVSamplefacedetection依賴于庫工程openCVLibrary340繁仁,而庫工程openCVLibrary340的build.gradle配置也需要修改涉馅。這里不再贅述,找到openCVLibrary340下的build.gradle進行修改即可黄虱。

修改完成后再次進行”Gradle project sync”稚矿,這一次”Gradle Sync”沒有報錯,隨后AS會進行”Gradle build”悬钳,也順利完成盐捷。

3. jni的配置

怎樣解決上面出現(xiàn)的問題?
首先默勾,我們需要先配置NDK的路徑碉渡,點擊File->Project Structure,在如下的界面上配置NDK的路徑母剥。

然后滞诺,在左側(cè)的項目窗口中選中openCVSamplefacedetection,右鍵點擊”Link C++ Project with Gradle”环疼,在彈出的窗口中按照下圖選擇习霹,點擊”O(jiān)K”。


右擊

打開Android.mk文件


ok炫隶,即可淋叶,會在gradle里面生成以下代碼


 externalNativeBuild {
        ndkBuild {
            path 'src/main/jni/Android.mk'
        }
    }

接下來,在左右的項目窗口中的“External Build Files”下伪阶,選擇Android.mk煞檩,修改OpenCV.mk的路徑:

include ../../sdk/native/jni/OpenCV.mk

修改后的路徑為处嫌,當然你需要根據(jù)自己電腦上的OpenCV4Android路徑進行配置:

 include D:\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk

在第12行的ndk部分加入以下的聲明:

  abiFilters "armeabi-v7a"

最終得到:

  ndk {
            moduleName "detection_based_tracker"
            abiFilters "armeabi-v7a"
        }

至此,整個jni部分的配置就全部完成斟湃,這時再點擊”構建“熏迹,可以發(fā)現(xiàn)已經(jīng)可以生成成功。

二凝赛、剔除OpenCV Manager依賴

在上一小節(jié)中注暗,我們已經(jīng)可以成功地配置fd工程,并且編譯生成都成功墓猎,此時我們可以將apk部署到手機上進行運行捆昏。但是等等,你還想被OpenCV Manager所困擾嗎毙沾?說實話屡立,每次我想要找到適合自己手機的OpenCV Manager,都要上網(wǎng)查一大堆資料搀军,費時又費勁。

那么接下來我就基于face-detection工程勇皇,給大家分享一個去掉OpenCV Manager依賴的方法罩句。

1、把OpenCV sdk for Android文件下F:\OpenCV-android-sdk\sdk\native下的libs文件夾拷貝到你的安卓項目下敛摘,即自己的項目\src\main下面门烂,并且將libs改名為 jniLibs(需要)
2、將OpenCV-android-sdk\samples\image-manipulations\res\layout下的xml文件拷貝到自己的項目\src\main\res下面(不需要也行)
3兄淫、將OpenCV-android-sdk\samples\image-manipulations\src\org\opencv\samples\imagemanipulations下的java文件拷到自己的項目\src\main\java\你 屯远,MainActivity所在的包名,即和MainActivity同級目錄(我改的是demo捕虽,沒加)
4慨丐、在項目清單文件中為剛才導入的java文件進行配置,加上相應的權限(看demo)

gradle:

 sourceSets.main {
        jniLibs.srcDir 'src/main/libs' //set .so files directory to libs
        jni.srcDirs = [] //disable automatic ndk-build call
    }

三泄私、常見問題

1房揭、openCV默認是橫屏,改成豎屏不全屏晌端,豎屏無法識別人臉
2捅暴、openCV Demo 里面沒有獲取圖片的地方
3、OpenCV Android 打開前置后置攝像頭

1咧纠、攝像頭豎屏全屏的設置

在CameraBridgeViewBase.java 文件修改 deliverAndDrawFrame()函數(shù)中蓬痒,修改以下部分

if (canvas != null) {  
    canvas.rotate(90,0,0);  
    float scale = canvas.getWidth() / (float)mCacheBitmap.getHeight();  
    float scale2 = canvas.getHeight() / (float)mCacheBitmap.getWidth();  
    if(scale2 > scale){  
        scale = scale2;  
    }  
    if (scale != 0) {  
        canvas.scale(scale, scale,0,0);  
    }  
    canvas.drawBitmap(mCacheBitmap, 0, -mCacheBitmap.getHeight(), null);  
   // canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);  
    Log.d(TAG, "mStretch value: " + mScale);  
  
  /*  if (mScale != 0) { 
        canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()), 
                new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2), 
                        (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2), 
                        (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()), 
                        (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null); 
    } else { 
        canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()), 
                new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2, 
                        (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, 
                        (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(), 
                        (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null); 
    }*/  

因為opencv要在橫屏時才能得到較好的結果,那么我可以先把豎屏時得到的圖像順時針旋轉(zhuǎn)90度漆羔,這樣就和橫屏時一樣了梧奢,然后我在把得到識別綠框的圖像逆時針旋轉(zhuǎn)90度狱掂,再輸出這樣就能做到豎屏時實現(xiàn)人臉檢測了。
所以修改FaActivity中的onCameraViewStarted和onCameraFrame()函數(shù)修改如下

   Mat Matlin, gMatlin;
    int absoluteFaceSize;

    public void onCameraViewStarted(int width, int height) {
        //        mGray = new Mat();
        //        mRgba = new Mat();

        mRgba = new Mat(width, height, CvType.CV_8UC4);
        mGray = new Mat(height, width, CvType.CV_8UC4);
        Matlin = new Mat(width, height, CvType.CV_8UC4);
        gMatlin = new Mat(width, height, CvType.CV_8UC4);

        absoluteFaceSize = (int) (height * 0.2);
    }

    int faceSerialCount = 0;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame InputFrame) {
        mGray = InputFrame.gray();
        mRgba = InputFrame.rgba();
        int rotation = mOpenCvCameraView.getDisplay().getRotation();

        //使前置的圖像也是正的
        Core.flip(mRgba, mRgba, 1);
        Core.flip(mGray, mGray, 1);

        //MatOfRect faces = new MatOfRect();

        if (rotation == Surface.ROTATION_0) {
            MatOfRect faces = new MatOfRect();
            Core.rotate(mGray, gMatlin, Core.ROTATE_90_CLOCKWISE);
            Core.rotate(mRgba, Matlin, Core.ROTATE_90_CLOCKWISE);
            if (mJavaDetector != null) {
                mJavaDetector.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
    
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
            Core.rotate(Matlin, mRgba, Core.ROTATE_90_COUNTERCLOCKWISE);

        } else {
            MatOfRect faces = new MatOfRect();
            if (mJavaDetector != null)
                mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
                        new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());

            Rect[] faceArray = faces.toArray();

       
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(mRgba, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
        }

        return mRgba;
    }

2粹断、捕獲人臉后自動拍照

捕獲人臉后自動拍照符欠,這個需求可能是最最常見的了,那在OpenCV里要如何實現(xiàn)呢瓶埋?首先我們來觀察一下JavaCameraView這個類希柿,它繼承自CameraBridgeViewBase

這個類,再往下翻會發(fā)現(xiàn)一個非常熟悉的Camera對象养筒,沒錯這個類里其實是使用了Android原生的API構造了一個相機對象(還好是原生的曾撤,至今還沒忘卻被JNI相機

一旦實現(xiàn)了PreviewCallback接口,肯定會有onPreviewFrame(byte[] frame,Camera camera)這個回調(diào)函數(shù)晕粪,這里面的字節(jié)數(shù)組frame對象挤悉,就是當前的視頻幀,注意這里是視頻幀巫湘,是YUV編碼的装悲,并不能直接轉(zhuǎn)換為Bitmap。這個回調(diào)函數(shù)在預覽過程中會一直被調(diào)用尚氛,那么只要確定了哪一幀有人臉诀诊,只需要在這里獲取就行,代碼如下:

private boolean takePhotoFlag = false;  
    @Override  
    public void onPreviewFrame(byte[] frame, Camera arg1) {  
        if (takePhotoFlag){  
            Camera.Size previewSize = mCamera.getParameters().getPreviewSize();  
            BitmapFactory.Options newOpts = new BitmapFactory.Options();  
            newOpts.inJustDecodeBounds = true;  
            YuvImage yuvimage = new YuvImage(  
                    frame,  
                    ImageFormat.NV21,  
                    previewSize.width,  
                    previewSize.height,  
                    null);  
            ByteArrayOutputStream baos = new ByteArrayOutputStream();  
            yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);  
            byte[] rawImage = baos.toByteArray();  
            BitmapFactory.Options options = new BitmapFactory.Options();  
            options.inPreferredConfig = Bitmap.Config.RGB_565;  
            Bitmap bmp = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);  
            try {  
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));  
                bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);  
                bos.flush();  
                bos.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
            bmp.recycle();  
            takePhotoFlag = false;  
        }  
        synchronized (this) {  
            mFrameChain[mChainIdx].put(0, 0, frame);  
            mCameraFrameReady = true;  
            this.notify();  
        }  
        if (mCamera != null)  
            mCamera.addCallbackBuffer(mBuffer);  
    }  

這里我們先在外層聲明一個布爾類型的變量阅嘶,在無限的回調(diào)過程中属瓣,一旦次布爾值為真,就對該視頻幀保存為文件讯柔,上面的代碼就將YUV視頻幀轉(zhuǎn)換為Bitmap對象的方法抡蛙,然后將Bitmap存成文件,當然這也的結構不太合理魂迄,我只是為了展示方便這樣書寫粗截。

現(xiàn)在已經(jīng)可以抓取照片了,那么如何才能判斷是不是有人臉來修改這個布爾值呢极祸,我們再定義這樣一個方法:</pre>

public void takePhoto(String name){  
       fileName = name;  
       takePhotoFlag = true;  
   }  

一旦調(diào)用了takePhoto這個方法慈格,傳入一個保存路徑,就能修改此布爾值遥金,完成拍照浴捆,我們離完成越來越接近了。那么回到我們一開始的Activity稿械,這里面包含剛剛修改的

JavaCameraView對象选泻,可以對他進行操作。然后找到Activity的onCameraFrame回調(diào)函數(shù),修改為:

int faceSerialCount = 0;  
   @Override  
   public Mat onCameraFrame(Mat aInputFrame) {  
       Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);  
       MatOfRect faces = new MatOfRect();  
       if (cascadeClassifier != null) {  
           cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2,  
                   new Size(absoluteFaceSize, absoluteFaceSize), new Size());  
       }  
       Rect[] facesArray = faces.toArray();  
       int faceCount = facesArray.length;  
       if (faceCount > 0) {  
           faceSerialCount++;  
       } else {  
           faceSerialCount = 0;  
       }  
       if (faceSerialCount > 6) {  
           openCvCameraView.takePhoto("sdcard/aaa.jpg");  
           faceSerialCount = -5000;           
       }  
       for (int i = 0; i < facesArray.length; i++) {  
           Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);  
       }  
       return aInputFrame;  
   }  

一旦該變量大于0页眯,就讓faceSerialCount自增梯捕,else的話就清零,如果faceSerialCount>6就調(diào)用剛才我們定義的takePhoto方法進

3窝撵、OpenCV Android 打開前置后置攝像頭

  mOpenCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);
//前置攝像頭 CameraBridgeViewBase.CAMERA_ID_BACK為后置攝像頭  

兼容性適配

名詞解析:
NDK:Native Development Kit
JNI:Java Native Interface
ABI: Application Binary Interface 應用二進制接口

1傀顾、Android Studio使用so庫

1、使用和eclipse一樣在libs目錄下新建armeabi目錄的方式

需要在build.gradle中添加指定jni庫目錄的語句

sourceSets {
   main.jniLibs.srcDirs = ['libs']  //指定libs為jni的存放目錄
}
2碌奉、使用AS默認的位置:src/main/jniLibs

直接在src/main/下新建jniLibs目錄短曾,將armeabi等目錄放到該目錄下即可
備注:AS可以直接右鍵新建同目錄下的jniLibs目錄,但該目錄不是編譯好的庫文件目錄赐劣,而是未編譯的本地代碼文件的目錄(這里指的是與java同級的jni目錄嫉拐,放置cpp代碼的)


android支持的cpu架構(目前是七種)

cpu
armeabi 第5代 ARM v5TE,使用軟件浮點運算魁兼,兼容所有ARM設備婉徘,通用性強,速度慢
armeabi-v7a 第7代 ARM v7咐汞,使用硬件浮點運算盖呼,具有高級擴展功能
arm64-v8a 第8代,64位化撕,包含AArch32塌计、AArch64兩個執(zhí)行狀態(tài)對應32、64bit
x86 intel 32位侯谁,一般用于平板
x86_64 intel 64位阻塑,一般用于平板
mips 少接觸
mips64 少接觸
安裝時的兼容性檢查:

安裝到系統(tǒng)中后蚣旱,so文件會被提取在:data/app/com.xxxxxxxx.app-x/lib/目錄下(5.0版本)、/data/app-lib/目錄下(4.2版本)却紧,其中armeabi和armeabi-v7a會生成arm目錄贱傀,arm64-v8a會生成arm64目錄惨撇。
安裝app的時候,如果app使用了so文件府寒,而不存在適合本機cpu架構的so文件魁衙,會報如下錯誤:
Installation failed with message INSTALL_FAILED_NO_MATCHING_ABIS.
例如:在x86模擬器上就必須有x86版本的so文件夾。不然無法安裝成功株搔。

運行時的兼容性檢查:

1剖淀、檢查目標目錄下是否存在的so庫文件
2、檢查存在的so文件是否符合當前cpu架構纤房。
對于情況一纵隔,一般規(guī)避的做法是:保證jnilibs目錄下x86、x84_64、armeabi捌刮、armeabi-v7a碰煌、arm64-v8a等目錄下的文件名稱數(shù)量是一致的。
例如:項目中使用了A绅作、B芦圾、C三個第三方庫。其中A俄认、B提供了armebi以及arm64-v8a版本的庫文件个少,而C只提供了armebi、armebi-v7a版本的庫文件梭依。這時候只能夠刪除原有的arm64-v8a目錄稍算,保留armeabi目錄,一般arm64的手機都能兼容使用armeabi版本的庫役拴『剑或者復制一份armeabi的so文件到缺少的目錄中(推薦)。

生成so文件:

NDK交叉編譯時選定APP_ABI := armeabi x86 ...可以生成支持相應芯片的so文件河闰。APP_ABI := all生成支持所有芯片指令集(目前七種)so文件科平。

Android加載so文件規(guī)則:

當你只提供了armeabi目錄時,armeabi-v7a姜性、arm64-v8a架構的程序都會去armeabi里尋找瞪慧,而當你同時也提供了armeabi-v7a、armeabi-v8a目錄部念,而里面又不存在對應的so庫時弃酌,系統(tǒng)就不會再去armeabi里面尋找了,直接找不到報錯儡炼。其他平臺也是如此妓湘。這里我踩了不少的坑,切記乌询。
一般來說榜贴,一些比較有名的第三方庫都會提供armeabi、armeabi-v7a妹田、x86這三種類型的so文件唬党,同時擁有這三種版本的app可以在所有機型上運行。另外鬼佣,越來越多的SDK會同時提供arm64-v8a版本驶拱。只包含armeabi的項目也可以在所有設備上運行。


2晶衷、ABI

Application.mk 文件如下

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a       #這句是設置生成的cpu指令類型屯烦,提示坷随,目前絕大部分安卓手機支持armeabi,libs下太多類型驻龟,編譯進去 apk 包會過大
APP_PLATFORM := android-8    #這句是設置最低安卓平臺温眉,可以不弄 

3、關于abiFilters的使用

在app的gradle的defaultConfig里面加上這么一句

ndk {
    abiFilters  "armeabi-v7a"  // 指定要ndk需要兼容的架構(這樣其他依賴包里mips,x86,armeabi,arm-v8之類的so會被過濾掉)
}

這句話的意思就是指定ndk需要兼容的架構翁狐,把除了v7a以外的兼容包都過濾掉类溢,只剩下一個v7a的文件夾。

以上是一種ABI的添加露懒,多種如下

APP_ABI :=armeabi-v7a arm64-v8a armeabi  mips mips64 x86 x86_64 //Application.mk中空格分開

gradle中逗號分開

 ndk {
            moduleName "detection_based_tracker"
            abiFilters "armeabi-v7a","arm64-v8a","armeabi","mips","mips64","x86","x86_64"
        }

官方說

參考文章

Android - OpenCV library
Android Camera動態(tài)人臉識別+人臉檢測基于OpenCV(無需OpenCVManager) - CSDN博客
Android Studio-—使用OpenCV的配置方法和demo以及開發(fā)過程中遇到的問題解決 - 奮斗者—cyf - 博客園
關于opencv的人臉識別的Demo配置(android端不需要Manager) - 簡書
Android Studio配置并運行OpenCV4Android的face-detection - Android移動開發(fā)技術文章_手機開發(fā) - 紅黑聯(lián)盟
Android NDK 入門與實踐
Android.mk | Android Developers
使用AndroidStudio編譯NDK的方法及錯誤解決方案 - 爐火純青 - 博客園
NDK各版本下載 - CSDN博客
OpenCV Android 打開前置后置攝像頭 - CSDN博客
OpenCV學習筆記(七)—— OpenCV for Android實時圖像處理 - CSDN博客
【安卓隨筆】使用OpenCV進行人臉跟蹤和自動拍照 - CSDN博客
Android OpenCV 實例筆記3 -- 攝像頭豎屏全屏的設置,更新完整代碼 - CSDN博客
OpenCV on Android 開發(fā) (4)豎屏預覽圖像問題解決方法-續(xù) - 簡書

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闯冷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子懈词,更是在濱河造成了極大的恐慌蛇耀,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坎弯,死亡現(xiàn)場離奇詭異纺涤,居然都是意外死亡,警方通過查閱死者的電腦和手機抠忘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門撩炊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人崎脉,你說我怎么就攤上這事拧咳。” “怎么了囚灼?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵骆膝,是天一觀的道長。 經(jīng)常有香客問我灶体,道長谭网,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任赃春,我火速辦了婚禮,結果婚禮上劫乱,老公的妹妹穿的比我還像新娘织中。我一直安慰自己,他們只是感情好衷戈,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布狭吼。 她就那樣靜靜地躺著,像睡著了一般殖妇。 火紅的嫁衣襯著肌膚如雪刁笙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音疲吸,去河邊找鬼座每。 笑死,一個胖子當著我的面吹牛摘悴,可吹牛的內(nèi)容都是我干的峭梳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蹂喻,長吁一口氣:“原來是場噩夢啊……” “哼葱椭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起口四,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤孵运,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蔓彩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體治笨,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年粪小,在試婚紗的時候發(fā)現(xiàn)自己被綠了大磺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡探膊,死狀恐怖杠愧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逞壁,我是刑警寧澤流济,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站腌闯,受9級特大地震影響绳瘟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜姿骏,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一糖声、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧分瘦,春花似錦蘸泻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至去团,卻和暖如春抡诞,著一層夾襖步出監(jiān)牢的瞬間穷蛹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工昼汗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肴熏,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓乔遮,卻偏偏與公主長得像扮超,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蹋肮,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

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