太阳能面板组件EL图像隐裂识别(一)

EL图像检测是太阳能面板组件生产过程中必不可少的一环,以往的方式是通过肉眼观察不良情况,但生产效率较低,容易漏判或错判。这里采用数字图像处理的方式自动检测。针对这个场景,传统的图像处理泛化能力较差,调参复杂,只能处理特殊的场景,比如单晶EL,对多晶、切半、叠片等效果并不太好。而深度学习的方式可完全胜任各种场合的多种不良检测。这里仅简单介绍下传统方法的处理方式,后面有时间再介绍深度学习的方式。希望对相似场景的图像识别有启发或借鉴意义。

先来两张组件的EL图像(单晶看起来还是比较干净的),单晶的不良比较明显主要是隐裂,为了便于看出多晶的不良,这里附上了深度学习检测的多晶结果。


单晶EL(10*6规格)原始图

多晶EL(12*6规格)原始图

多晶EL(12*6)深度学习检测结果

以下将按照处理顺序进行介绍如何以传统图像处理方法识别单晶隐裂:
思路:

原始组件图直接处理不太好办,所以想把它切成电池片,针对电池片想要识别隐裂并判断其范围,我们需要一个干净的背景,即只留下隐裂,其实不同的电池片很难做到统一的效果。不难发现横向的珊线影响是比较大的,必须首先去除,然后通过二值化处理应该就差不多了,再对图像做水平和竖直的像素投影,基于像素分布规律设计合理的判断逻辑应该就能找到隐裂的起始与终止边界。

第一步:对组件切图

电池片大小相等分布均匀,最简单的思路是直接等分切割,但实际中组件最外边的黑框宽度是不确定的,对切图效果会有影响。因此,要么识别四周黑边的范围然后等分切图,要么识别每个电池片的边界切图,我这里采用第一种方式。话不多说先上代码:

class cut_img(object):
    def __init__(self):
        pass
    def _save_max_objects(self,img):
        labels = measure.label(img)  # 返回打上标签的img数组
        jj = measure.regionprops(labels)  # 找出连通域的各种属性,注意,这里jj找出的连通域不包括背景连通域
        if len(jj) == 1:
            out = img
        else:  # 通过与质心之间的距离进行判断
            num = labels.max()  # 连通域的个数
            del_array = np.array([0] * (num + 1))  # 生成一个与连通域个数相同的空数组来记录需要删除的区域(从0开始,所以个数要加1)
            initial_area = jj[0].area
            save_index = 1  # 初始保留第一个连通域
            for k in range(1, num):  # TODO:全黑图像,暂时不处理
                if initial_area < jj[k].area:
                    initial_area = jj[k].area
                    save_index = k + 1
            del_array[save_index] = 1
            del_mask = del_array[labels]
            out = img * del_mask
        return out
    
    def _black_edges(self,image):
        height, width = image.shape[:2]
        size = (int(width * 0.25), int(height * 0.25))#缩放
        shrink = cv2.resize(image, size, interpolation=cv2.INTER_AREA)
        gray = cv2.cvtColor(shrink, cv2.COLOR_BGR2GRAY)
        ret2, image_binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        ret, binary = cv2.threshold(gray, ret2 * 0.85, 255, cv2.THRESH_BINARY)#二值化
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 8))#定义矩形kernel
        iOpen = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
        iClose = cv2.morphologyEx(iOpen, cv2.MORPH_CLOSE, kernel)#执行开闭预算去除组件内电池片珊线与边界
        dst1 = self._save_max_objects(iClose)#计算符合条件的联通区
        bbox = measure.regionprops(dst1)[0]['bbox']
        lu = (bbox[1] * 4, bbox[0] * 4);rd = (bbox[3] * 4, bbox[2] * 4)#坐标乘以缩放值
        return lu,rd

总体思路是通过二值化及开闭形态学运算形成如下图的联通区,然后提取联通区计算坐标即可。


组件黑框联通区

根据上述代码计算的坐标切出只含电池片的片区,然后根据组件规格进行等分切图。

  img = Image.open(r'xxxxxxxxxxxxxxxx.jpg')
  image = cv2.imread(r'xxxxxxxxxxxxxxxx.jpg')
    w = 10;h=6
    lu, rd = _black_edges(image)
    region = (lu[0],lu[1],rd[0],rd[1])
    cropImg = img.crop(region)
    width, height = cropImg.size
    item_width = int(width / w)
    item_height = int(height / h)
    for j in range(0,w):
        for i in range(0,h):
            box = (j*item_width,i*item_height,(j+1)*item_width,(i+1)*item_height)
            imbox = cropImg.crop(box)
            imbox.save('cut_test' + '/' + str(i+1)+'_'+str(j+1) + '_result.jpg',quality=95)

切出的电池片如下:

2_10_result.jpg
4_2_result.jpg

效果还凑合,不影响后续操作。识别完成后,再反向拼接起来即可。下面就以4_2_result.jpg为例进行处理。

第二步:对灰度图进行腐蚀膨胀等形态学运算突出珊线

这一步主要是处理珊线,先不管隐裂,处理后,珊线越明显越好。先进行灰度化再进行腐蚀膨胀操作,这里关键是定义好kernel,因为珊线是横向的因此核的形状最好有所选择。代码如下:

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
rows,cols=gray.shape
scale = 20
kernel  = cv2.getStructuringElement(cv2.MORPH_RECT,(cols//scale,1))#定义kernel
eroded = cv2.erode(gray,kernel,iterations = 3)#横向腐蚀三次
dilatedcol = cv2.dilate(eroded,kernel,iterations = 3)#横向膨胀,迭代三次,这里也可进行开闭运算,有兴趣可以试下
ret2, image_binary = cv2.threshold(dilatedcol, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)#计算合适的二值化阈值
 _, binary = cv2.threshold(dilatedcol, ret2*0.85, 255, cv2.THRESH_BINARY)#效果好的话,这里应该留下清晰的珊线
cv2.imwrite('gray.jpg',gray)#灰度图
cv2.imwrite('eroded.jpg',eroded)#横向腐蚀图
cv2.imwrite('dilate.jpg',dilatedcol)#膨胀
cv2.imwrite('binary.jpg',binary)#二值化

为了清楚看到整个过程,这里保存了中间结果,如下图所示:


binary.jpg
dilate.jpg
eroded.jpg
gray.jpg
第三步:灰度图与珊线图进行像素差运算去除主珊线

珊线突出后可以通过和原灰度图进行相减(或者逻辑与)运算进行擦除:

sub = cv2.subtract(binary,gray)
cv2.imwrite('subtract.jpg',sub)#相减效果
subtract.jpg

正常的话应该可以进行二值化了,但可以看到珊线上下还有明显的间断亮色带这会影响二值化效果,因此需要去除这些色带,腐蚀膨胀操作不够直接,这里我对珊线上下像素行赋0,相当于直接拓宽了珊线。代码如下:

def _img_mean(imgs):
        '''
        选取行列中0值占比超70%的行列上下拓展,类似于膨胀操作,70%为经验阈值,
        大部分图片都是适用的,特殊情况可以自己调节
        '''
        img = imgs.copy()
        height, width = img.shape[:2]
        spi = [];czi = []
        for y in range(0, height):
            if Counter(img[y])[0]/width > 0.70:
                spi.append(y)
        for num in spi:#以下赋值不建议采用切片方式,否则在首尾可能报错
            #对行赋0,根据效果上下宽度可调
            try:
                img[num] = 0
                img[num+1] = 0
                img[num-1] = 0
                img[num+2] = 0
                img[num-2] = 0
                img[num+3] = 0
                img[num-3] = 0
                img[num+4] = 0
                img[num-4] = 0
            except:
                pass
        for x in range(0, width):
            if Counter(img[:,x])[0]/width > 0.70:
                czi.append(x)
        for num in czi:
            #对列赋0,根据效果上下宽度可调
            try:
                img[:,num] = 0
                img[:,num+1] = 0
                img[:,num-1] = 0
                img[:,num+2] = 0
                img[:,num-2] = 0
                img[:,num+3] = 0
                img[:,num-3] = 0
                img[:,num-8:num] = 0
            except:
                pass
        return img,np.mean(img)

具体扩宽的范围可以根据实际情况调整,一般稍微大一些珊线去除比较干净,太大就有可能吞噬真正的隐裂范围,需要酌情处理。


珊线拓宽后的效果
第四步:再次二值化突出隐裂

接下来就可以做二值化了,这一步选择合适的阈值,尽量只留下隐裂,背景越干净接下来投影图判断范围就更简单。关于阈值选择,这里以像素均值为参考,因为真正的隐裂明显发暗,像素值应该低于像素均值。代码如下:

r, b = cv2.threshold(subs, mean*alpha, 255, cv2.THRESH_BINARY_INV)#反二值化,阈值alpha=1.49可根据实际效果调整,最好的效果是只留下隐裂

这里的alpha是自己指定的系数我这里取1.49可以作为默认值,可直接决定二值化效果。


只保留隐裂的二值化效果.jpg

其实最右侧的间断黑边也是一种不良叫虚焊,实际场景中也需要检出,因为这里只做隐裂,因此暂时忽略其存在。

第五步:做水平和垂直的像素投影

隐裂区域像素值和背景区像素值有明显差异,表现在像素分布上就是类似于断崖式的间断区间,根据这个规律可以判断隐裂的范围。

def get_x(w,v):
        incol = 1
        mis = np.min(v)
        result = []
        try:
            for i in range(0,w):
                if incol==1 and abs(v[i]-mis)<=8:#根据实际效果可依照投影图czty.jpg调整这个值,这里暂时选择8
                    start = i#满足条件,记录起始位置
                    incol=0
                elif incol == 0 and ((i - start) >= int(len(v)/4)) and abs(v[i]-mis)<=8 :#int(len(v)/4))是隐裂长度四分之一电池片,改值可调
                    end = i
                    result.append((start,end))
                    incol=1
            return result[0]
        except:
            return 0,0
    
    def get_y(h,z):
        incol = 1
        result = []
        ms = np.min(z)
        try:
            for i in range(0,h):
                if incol==1 and abs(z[i]-ms)<5:#根据实际效果可依照投影图spty.jpg调整这个值,这里暂时选择5
                    start = i
                    incol=0
                elif incol == 0 and (i - start >= int(len(z)/5)) and abs(z[i]-ms)<5:
                    end = i
                    result.append((start,end))
                    incol=1
            return result[0]
        except:
            return 0,0
    
    def czty(binary):
        height, width = binary.shape[:2]
        v = [0]*width
        a = 0
        for x in range(0, width):
            for y in range(0, height):
                if binary[y,x] == 0:
                    a = a + 1
                else :
                    continue
            v[x] = a
            a = 0
        emptyImage = np.zeros((height, width, 3), np.uint8) #创建空白图
        for x in range(0,width):
            for y in range(0, v[x]):
                b = (255,255,255)
                emptyImage[y,x] = b
        #count
        x1,x2 = get_x(width,v)
      
        cv2.imwrite('czty.jpg',emptyImage)
        return x1,x2
    
    def spty(binary):
        height, width = binary.shape[:2]
        a = 0;z = [0]*height
        emptyImage = np.zeros((height, width, 3), np.uint8) 
        for y in range(0, height):
            for x in range(0, width):
                if binary[y,x] == 0:
                    a = a + 1
                else :
                    continue
            z[y] = a
            a = 0
        for y in range(0,height):
            for x in range(0, z[y]):
                b = (255,255,255)
                emptyImage[y,x] = b
        y1,y2 = get_y(height,z)
        
        cv2.imwrite('spty.jpg', emptyImage)
        return y1,y2

 x1,x2 = self.czty(b)#计算垂直方向像素投影坐标
 y1,y2 = self.spty(b)#计算水平方向像素投影坐标

投影图如下:


垂直投影
水平投影

我在像素投影图中大致标出了对应的区域,判断逻辑需要找出对应的坐标点。
水平投影需对像素矩阵进行纵向遍历,首先定义一个起始点记录标志incol = 1,同样是以整个图像的像素均值ms为参考(注意这里所说的像素是像素值为0的个数),比较该行像素与ms的大小,这里选的阈值为5,低于这个值我们认为已进入隐裂范围。记录这个起始点后要把incol置0,因为后面有大部分满足该条件的点,接下来就开始判断终点;这里假设隐裂长度都不小于1/5的电池片宽度,低于此值的不做终点判断。当某行像素达到条件后,即认为找到终点,然后记录开始和结束位置,因为可能有多个隐裂出现,把位置元组加进一个list里,简单起见,这里只返回了第一个。垂直投影的判断逻辑类似这里不赘述了。计算坐标后画出隐裂位置:

s = cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imwrite('result.jpg',s)

下面给出判断效果


result.jpg

完整代码如下:

# =============================================================================
# 切图类,返回切图坐标
# =============================================================================
class cut_img(object):
    def __init__(self):
        pass
    def _save_max_objects(self,img):
        labels = measure.label(img)  # 返回打上标签的img数组
        jj = measure.regionprops(labels)  # 找出连通域的各种属性,注意,这里jj找出的连通域不包括背景连通域
        if len(jj) == 1:
            out = img
        else:  # 通过与质心之间的距离进行判断
            num = labels.max()  # 连通域的个数
            del_array = np.array([0] * (num + 1))  # 生成一个与连通域个数相同的空数组来记录需要删除的区域(从0开始,所以个数要加1)
            initial_area = jj[0].area
            save_index = 1  # 初始保留第一个连通域
            for k in range(1, num):  # TODO:全黑图像,暂时不处理
                if initial_area < jj[k].area:
                    initial_area = jj[k].area
                    save_index = k + 1
            del_array[save_index] = 1
            del_mask = del_array[labels]
            out = img * del_mask
        return out
    
    def _black_edges(self,image):
        height, width = image.shape[:2]
        size = (int(width * 0.25), int(height * 0.25))#缩放
        shrink = cv2.resize(image, size, interpolation=cv2.INTER_AREA)
        gray = cv2.cvtColor(shrink, cv2.COLOR_BGR2GRAY)
        ret2, image_binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        ret, binary = cv2.threshold(gray, ret2 * 0.85, 255, cv2.THRESH_BINARY)#二值化
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 8))#定义矩形kernel
        iOpen = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
        iClose = cv2.morphologyEx(iOpen, cv2.MORPH_CLOSE, kernel)#执行开闭预算去除组件内电池片珊线与边界
        dst1 = self._save_max_objects(iClose)#计算符合条件的联通区
        bbox = measure.regionprops(dst1)[0]['bbox']
        lu = (bbox[1] * 4, bbox[0] * 4);rd = (bbox[3] * 4, bbox[2] * 4)#坐标乘以缩放值
        return lu,rd


class alg_cell():
    def __init__(self,img,alfa=1.41,save_temp_img=True):
        self.save_temp_img = save_temp_img
        self.alfa = alfa
        self.img = img
        self.gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
        self.rows,self.cols=self.gray.shape
        self.scale = 20
        self.kernel  = cv2.getStructuringElement(cv2.MORPH_RECT,(self.cols//self.scale,1))#定义kernel
        self.eroded = cv2.erode(self.gray,self.kernel,iterations = 3)#横向腐蚀三次
        self.dilatedcol = cv2.dilate(self.eroded,self.kernel,iterations = 3)#横向膨胀,迭代三次,这里也可进行开闭运算,有兴趣可以试下
        self.ret2, image_binary = cv2.threshold(self.dilatedcol, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)#计算合适的二值化阈值
        _, self.binary = cv2.threshold(self.dilatedcol, self.ret2*0.85, 255, cv2.THRESH_BINARY)#效果好的话,这里应该留下清晰的珊线
        if self.save_temp_img:
            cv2.imwrite('gray.jpg',self.gray)#灰度图
            cv2.imwrite('eroded.jpg',self.eroded)#横向腐蚀图
            cv2.imwrite('dilate.jpg',self.dilatedcol)#膨胀
            cv2.imwrite('binary.jpg',self.binary)#二值化
            
    def _img_mean(self,imgs):
        '''
        选取行列中0值占比超70%的行列上下拓展,类似于膨胀操作,70%为经验阈值,
        大部分图片都是适用的,特殊情况可以自己调节
        '''
        img = imgs.copy()
        height, width = img.shape[:2]
        spi = [];czi = []
        for y in range(0, height):
            if Counter(img[y])[0]/width > 0.70:
                spi.append(y)
        for num in spi:#以下赋值不建议采用切片方式,否则在首尾可能报错
            #对行赋0,根据效果上下宽度可调
            try:
                img[num] = 0
                img[num+1] = 0
                img[num-1] = 0
                img[num+2] = 0
                img[num-2] = 0
                img[num+3] = 0
                img[num-3] = 0
                img[num+4] = 0
                img[num-4] = 0
            except:
                pass
        for x in range(0, width):
            if Counter(img[:,x])[0]/width > 0.70:
                czi.append(x)
        for num in czi:
            #对列赋0,根据效果上下宽度可调
            try:
                img[:,num] = 0
                img[:,num+1] = 0
                img[:,num-1] = 0
                img[:,num+2] = 0
                img[:,num-2] = 0
                img[:,num+3] = 0
                img[:,num-3] = 0
                img[:,num-8:num] = 0
            except:
                pass
        return img,np.mean(img)
    
    def get_x(self,w,v):
        incol = 1
        mis = np.min(v)
        result = []
        try:
            for i in range(0,w):
                if incol==1 and abs(v[i]-mis)<=8:#根据实际效果可依照投影图czty.jpg调整这个值,这里暂时选择8
                    start = i#满足条件,记录起始位置
                    incol=0
                elif incol == 0 and ((i - start) >= int(len(v)/4)) and abs(v[i]-mis)<=8 :#int(len(v)/4))是隐裂长度四分之一电池片,改值可调
                    end = i
                    result.append((start,end))
                    incol=1
            return result[0]
        except:
            return 0,0
    
    def get_y(self,h,z):
        incol = 1
        result = []
        ms = np.min(z)
        try:
            for i in range(0,h):
                if incol==1 and abs(z[i]-ms)<5:#根据实际效果可依照投影图spty.jpg调整这个值,这里暂时选择5
                    start = i
                    incol=0
                elif incol == 0 and (i - start >= int(len(z)/5)) and abs(z[i]-ms)<5:
                    end = i
                    result.append((start,end))
                    incol=1
            return result[0]
        except:
            return 0,0
    
    def czty(self,binary):
        height, width = binary.shape[:2]
        v = [0]*width
        a = 0
        for x in range(0, width):
            for y in range(0, height):
                if binary[y,x] == 0:
                    a = a + 1
                else :
                    continue
            v[x] = a
            a = 0
        emptyImage = np.zeros((height, width, 3), np.uint8) #创建空白图
        for x in range(0,width):
            for y in range(0, v[x]):
                b = (255,255,255)
                emptyImage[y,x] = b
        #count
        x1,x2 = self.get_x(width,v)
        if self.save_temp_img:
            cv2.imwrite('czty.jpg',emptyImage)
        return x1,x2
    
    def spty(self,binary):
        height, width = binary.shape[:2]
        a = 0;z = [0]*height
        emptyImage = np.zeros((height, width, 3), np.uint8) 
        for y in range(0, height):
            for x in range(0, width):
                if binary[y,x] == 0:
                    a = a + 1
                else :
                    continue
            z[y] = a
            a = 0
        for y in range(0,height):
            for x in range(0, z[y]):
                b = (255,255,255)
                emptyImage[y,x] = b
        y1,y2 = self.get_y(height,z)
        if self.save_temp_img:
            cv2.imwrite('spty.jpg', emptyImage)
        return y1,y2
        
    def start(self):
        '''
        第一步:对灰度图进行腐蚀膨胀等形态学运算突出珊线
        第二步:进行合理的二值化,留下清晰的珊线图,这两步均在类初始化函数__init__完成
        第三步:灰度图与珊线图进行像素差运算(逻辑与也可以),去除主珊线
        第四步:设计算法,对沿主珊线上下的不连续焊条带进行擦除
        第五步:进行反二值化,尽量只留下隐裂
        第六步:做水平和垂直方向的像素投影
        第七步:设计算法,计算水平和竖直方向的长度坐标,最终效果需要精调这里
        '''
        sub = cv2.subtract(self.binary,self.gray)#相减消除主珊线
        subs,mean = self._img_mean(sub)#沿主珊线擦除不连续焊带
        r, b = cv2.threshold(subs, mean*self.alfa, 255, cv2.THRESH_BINARY_INV)#反二值化,阈值1.41可根据实际效果调整,最好的效果是只留下隐裂
        x1,x2 = self.czty(b)#计算垂直方向像素投影坐标
        y1,y2 = self.spty(b)#计算水平方向像素投影坐标
        if sum([x1,x2,y1,y2])==0:
            print('Normal!')
        else:
            s = cv2.rectangle(self.img, (x1, y1), (x2, y2), (0, 0, 255), 2)
            cv2.imwrite('result.jpg',s)
        if self.save_temp_img:
            cv2.imwrite('subtract.jpg',sub)#相减效果
            cv2.imwrite('subs_mean.jpg',subs)#去除珊线效果
            cv2.imwrite('subs_mean_b.jpg',b)#除珊线的二值化
        
# =============================================================================
# 测试,这里为测试方便没有给路径,默认图片读取和保存均在代码根目录进行
# =============================================================================
if __name__ == '__main__':
# =============================================================================
#     切图
# =============================================================================
#    img = Image.open(r'xxxxxx.jpg')
#    image = cv2.imread('xxxxxxx.jpg')
#    w = 10;h=6
#    lu, rd = _black_edges(image)
#    region = (lu[0],lu[1],rd[0],rd[1])
#    cropImg = img.crop(region)
#    width, height = cropImg.size
#    item_width = int(width / w)
#    item_height = int(height / h)
#    for j in range(0,w):
#        for i in range(0,h):
#            box = (j*item_width,i*item_height,(j+1)*item_width,(i+1)*item_height)
#            imbox = cropImg.crop(box)
#            imbox.save('cut_test' + '/' + str(i+1)+'_'+str(j+1) + '_result.jpg',quality=95)
# =============================================================================
# 隐裂检测    
# =============================================================================
    image = cv2.imread(r'4_2_result.jpg')
    test = alg_cell(image,alfa=1.49)
    test.start()

小结

其实传统方法识别隐裂已经比较吃力,主要的问题在于实际图像情况复杂,一套参数很难通用,导致方法的泛化性能很差,难以推广。深度学习则不同,经过大量的图片训练,在多种图像场景下都能工作的很好,且能识别多种不良。其庞大的参数规模使其具有很好的泛化性和抗干扰能力。下面贴两张深度学习的端到端识别多晶组件不良的效果图(深度学习识别单晶的效果远好于多晶),以后有时间再具体介绍。


组件多晶12*6
组件多晶12*6
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容