HDR基础知识汇总

摘自知乎:https://zhuanlan.zhihu.com/p/90093872

HDR - 高动态范围成像

高动态范围成像(HDRI或HDR)是一种用于成像和摄影的技术,用于再现比标准数字成像或摄影技术更大的动态范围的光度。虽然人眼可以适应广泛的光照条件,但大多数成像设备每个通道使用8位,因此我们只能使用256级。当我们拍摄真实世界的场景时,明亮的区域可能曝光过度,而黑暗的区域可能曝光不足,所以我们不能用一次曝光来捕捉所有的细节。HDR成像适用于每个通道使用8位以上的图像(通常是32位浮点值),允许更宽的动态范围。

获取HDR图像有不同的方法,但最常见的是使用不同曝光值拍摄的场景照片。要组合这些曝光,了解相机的响应函数是很有用的,有算法可以估计它。HDR图像合并后,必须将其转换回8位才能在通常的显示器上查看。这个过程被称为色调映射。当场景或相机的物体在镜头之间移动时,会出现额外的复杂性,因为不同曝光的图像应该被注册和对齐。

人类视觉与相机的成像亮度范围

人类视觉系统可以覆盖常见的自然场景的动态范围
数码相片在低光下的动态范围
数码相片在高光下的动态范围

上面三张图可以看出来,相机实际上能看到的高低亮度范围非常小,不足以覆盖真实世界的光线范围,HDR的基本原理就是从低曝光到高曝光,拍摄多张照片,融合起来,使一张图尽量把高光和黑暗的细节都表现出来。(注:上面图像标注有误,低曝光应该是只能覆盖高亮区域,高曝光只能覆盖暗区,其他区域会过曝)


image.png

基础HDR算法

对于raw图来说
image.png
对于RGB图来说要多两个步骤

RGB图像由于经过了系统的非线性处理(例如tone reproduction等),因此其像素值与场景的辐照度之间不再是线性关系:


RGB图像像素值和辐照度呈非线性关系

相机响应曲线

相机响应曲线是指相机在不同曝光下的输出亮度值与实际光照强度之间的关系曲线。相机响应曲线是相机的重要参数之一,它直接影响到相片的曝光效果。相机响应曲线通常可以通过测量相机的色彩响应来确定,色彩响应是指相机在不同色彩下的输出亮度值与实际光照强度之间的关系曲线。相机响应曲线通常是非线性的,因此在实际拍摄中需要根据实际情况进行曝光补偿,以达到理想的曝光效果。


image.png

在这个过程中,每张照片的像素值被还原到对应的光辐照度,然后多张照片的光辐照度用特定的权重加权平均,得到最后的辐照图

色调映射

在下面这张HDR图像中几个用方框标注的像素点的最大值和最小值比例超过了15000:1,是值域很宽广的矩阵.


image.png

但是我们通常的显示设备(比如你的LCD显示器)只是8位的,其动态范围非常有限


image.png

因此我们需要把HDR图像的值压缩到有限的范围——这个过程就叫做色调映射(tonemapping)
下图是线性映射和非线性映射的区别
image.png

HDRI

HDRI文件格式介绍(OpenEXR、RadianceRGBE、FloatTIFF)
HDRI(High-DynamicRange Image)就是记录采用了HDR技术的图象数据文件。常用的HDRI文件有OpenEXR、RadianceRGBE、FloatTIFF三种格式

OpenEXR文件格式

OpenEXR是由工业光魔(IndustrialLight & Magic)开发的一种HDR标准。OpenEXR文件的扩展名为.exr,常见的OpenEXR文件是FP16(16bitFloat Point,也被称为halfFloat Point)数据图像文件,每个通道的数据类型是FP16,一共四个通道64bpp,每个通道1个bit位用来标志“指数”,5个bit用来存放指数的值,10个bit存放色度坐标(u,v)的尾数,其动态范围从6.14× 10 ^ -5到6.41× 10 ^ 4。
在OpenEXR的算法里面共使用16bit来表示光照数据。虽然看起来和使用16bit亮度通道运算位数相同,但是OpenEXR巧妙的采用了1个bit位用来标志“指数”,5个bit用来存放指数的值,10个bit存放色度坐标的尾数。这样就轻易的解决了浮点数值由于位数少而精度不高的问题。大大的拓宽的在FP16下的动态范围。根据实际的计算结果:在正规化的情况下OpenEXR可以提供和人眼基本相同的动态范围,最暗到最亮是0.00006103515625(6.14 ×10 ^ -5)到65504(6.41 ×10 ^ 4),动态范围是9.03;非正规化条件下,OpenEXR可以提供从最暗到最亮的数值从0.000000059604644775390625(5.96 ×10 ^ -8 )到65504(6.41 ×10 ^ 4),化为动态范围表示就是12。
下面是Still写的OpenEXR读写代码,保存的.exr文件采用Zips压缩编码。

bool COpenExr::Load(const char fileName[], int& width, int& height, float** pixels)
{ 
std::vector<float> vecpixels;
if(!Load(fileName, width, height, vecpixels))
return false;
 
int num = width * height * 3;
*pixels = new float[num];
if(NULL == *pixels)
return false;
 
std::vector<float>::pointer ptr = &vecpixels[0];
memcpy(*pixels, ptr, num * 4); 
return true;
}
bool COpenExr::Load(const char fileName[], int& width, int& height, std::vector<float> &pixels)
{
Imf::Array<Imf::Rgba> pixelsdata;
bool bLoad = loadImage(fileName, width, height, pixelsdata);
if(!bLoad) return false;
for(int y = 0; y < height; y++)
{
int i = y * width;
for(int x = 0; x < width; x++)
{
int j = i + x;
const Imf::Rgba &rp = pixelsdata[j];
 
pixels.push_back( float(rp.r));
pixels.push_back( float(rp.g));
pixels.push_back( float(rp.b)); 
}
}
return true;
}
bool COpenExr::loadImage (const char fileName[], int& width, int& height, Imf::Array<Imf::Rgba>& pixels)
{
Imf::RgbaInputFile in (fileName);
Imath::Box2i dataWindow = in.dataWindow();
int dw, dh, dx, dy;
width = dw = dataWindow.max.x - dataWindow.min.x + 1;
height = dh = dataWindow.max.y - dataWindow.min.y + 1;
dx = dataWindow.min.x;
dy = dataWindow.min.y;
pixels.resizeErase (dw * dh);
in.setFrameBuffer (pixels - dx - dy * dw, 1, dw);
try
{
in.readPixels (dataWindow.min.y, dataWindow.max.y);
}catch (const exception &e)
{
std::cerr << e.what() << std::endl;
return false;
}
return true;
}
bool COpenExr::Save(const char fileName[], int width, int height, const float* pixels)
{
std::vector<float> vecpixels(pixels, pixels + width * height * 3);
return Save(fileName, width, height, vecpixels);
}
bool COpenExr::Save(const char fileName[], int width, int height, const std::vector<float> pixels)
{
Imf::Array<Imf::Rgba> pixelsdata;
pixelsdata.resizeErase(width * height);
for(int y = 0; y < height; y++)
{
int i = y * width;
for(int x = 0; x < width; x++)
{
int j = i + x;
 
half r = pixels[j * 3 ];
half g = pixels[j * 3 + 1];
half b = pixels[j * 3 + 2];
pixelsdata[j] = Imf::Rgba(r, g, b);
}
}
return SaveImage(fileName, width, height, pixelsdata);
}
bool COpenExr::SaveImage(const char fileName[], int width, int height, const Imf::Array<Imf::Rgba> &pixels)
{
Imf::RgbaOutputFile file (fileName, width, height);
file.setFrameBuffer(pixels, 1, width);
try
{
file.writePixels(height);
}catch(const exception &e)
{
std::cerr<< e.what() <<std::endl;
return false;
}
return true;
} 
Radiance RGBE文件格式

RGBE文件的扩展名为.hdr,RGBE正式名称为RadianceRGBE格式。这个本来是BR、FR等作为radiance材质的一种格式,也叫做radiancemap,后来成为流行的一种HDR格式。所谓E,就是指数。RadianceRGBE文件每个通道为8bitBYTE数据类型,4个通道一共是32bit。RGBE可以使用RLE压缩编码压缩,也可以不压缩。由文件头、RGBE数据组成。
文件头如下:
类型输出格式
char programtype[16]; //#?Radiance/n#Generated by still/n
float gamma; //1.0
float exposure; //1.0
字符串常量//FORMAT=32-bit_rle_rgbe/n/n
int nWidth, int nHeight //-Y nHeight +X nWidth/n

RGBE数据与HDRFP32(RGB)相互转换公式如下:
1、rgbe->FP32(RGB)
如果e为0, R = G= B = 0.0,否则:
R = r * 2^(e – 128 - 8);
G = g * 2^(e – 128 - 8);
B = b * 2^(e – 128 - 8);

2、FP32(RGB)-> rgbe
v = max(R, G, B);
如果v< 1e-32, r = g = b = e = 0, 否则:
将v用科学计算法表示成v = m * 2 ^ n ( 0 < m < 1):
r = R * m * 256.0/v;
g = G * m * 256.0/v;
b = B * m * 256.0/v;
e = n + 128;

Still注:
1、我们一般说HDR采用FP32,指的是HDR图象运算时候的内存数据类型,而RadianceRGBE文件采用8bitBYTE类型存储HDR数据。也就是说打开RadianceRGBE文件,要使用上面的公式1将RadianceRGBE文件的8bitBYTE文件数据转换为FP32的HDR内存数据进行运算;保存为RadianceRGBE文件时,要使用上面的公式2将HDR的FP32内存数据转换为RadianceRGBE的8bitBYTE文件数据进行保存。同理,OpenEXR文件的读写也存在将其FP16的文件数据到HDR的 FP32图象数据的转换;而下面将要讲的FloatTiff是不需要进行数据转换,直接将HDR的FP 32图象数据保存到TIFF文件中即可。
2、Radiance有多种文件格式,其官方库包含内容比较复杂,所以,实际的读写没有使用其官方库,而是使用了网络上一个简单的C语言读写类,Still并对其进行了部分修改(在文件头写入“Generatedby Still”)。

FloatTiff文件格式

Tiff文件的扩展名为.tif(.tiff),FloatTiff每个通道为FP32(32bit Float Point)类型,一共3个通道96bpp。用Tiff文件存储HDR数据,直接将HDR的FP32保存到TIFF文件中,有官方库可以利用。下面是Still写的代码样例,HDR数据我采用的是LZW压缩编码:

bool CFloatTiff::Load(const char fileName[], int& width, int& height, float** pixels)
{
TIFF* fp = NULL;
if((fp = TIFFOpen(fileName, "r")) == NULL)
return false;
 
//获取信息
uint16 bps, spp, datatype, photometric, compression, planarconfig, fillorder;
 
//每个通道占据的数据位数
if( (TIFFGetField(fp, TIFFTAG_BITSPERSAMPLE, &bps) == 0) || (bps != 32))
return false;
//每个象素的通道数目
if((TIFFGetField(fp, TIFFTAG_SAMPLESPERPIXEL, &spp) == 0) || (spp != 3))
return false;
//每个通道的数据类型
if((TIFFGetField(fp, TIFFTAG_SAMPLEFORMAT, &datatype) == 0) || (datatype != AMPLEFORMAT_IEEEFP))
return false;
//图像的数据采用的颜色模型
if((TIFFGetField(fp, TIFFTAG_PHOTOMETRIC, &photometric) == 0) || (photometric != PHOTOMETRIC_RGB))
return false;
TIFFGetField(fp, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(fp, TIFFTAG_IMAGELENGTH, &height);
int num = width * height * 3;
*pixels = new float[num];
if(NULL == *pixels)
return false;
 
if( TIFFReadEncodedStrip(fp, 0, *pixels, width * height * 3 * 4) == -1)
return false;
 
TIFFClose(fp);
return true;
}
bool CFloatTiff::Save(const char fileName[], int width, int height, const float* pixels)
{
if(NULL == pixels)
return false;
 
TIFF *fp = NULL;
 
if((fp = TIFFOpen(fileName, "w")) == NULL)
return false;
TIFFSetField(fp, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(fp, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(fp, TIFFTAG_COMPRESSION, COMPRESSION_LZW);//COMPRESSION_DEFLATE;
TIFFSetField(fp, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(fp, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(fp, TIFFTAG_BITSPERSAMPLE, 32);
TIFFSetField(fp, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(fp, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
if(TIFFWriteEncodedStrip(fp, 0, const_cast<float*>(pixels), width * height * 3 * 4) == -1)
return false;
TIFFClose(fp);
return true;
} 

HDR视频

HDR图像(High-Dynamic Range Image)即高动态范围图像,简称HDRI,它将每个曝光瞬间相对应最佳细节的LDR图像(Low-Dynamic Range,低动态范围)合成为最终的HDR图像;通俗来说,就是将同一个画面进行多次曝光,再合成为一张图像。HDR视频就是带有HDR特效的特殊视频,这种视频相比普通视频来说画面更加生动有质感。无论是HDR图像还是HDR视频,都是基于HDR技术的, HDR是一种概念,同时也是一种特殊的图像/视频文件格式。HDR的意义在于:让显示器画面更接近人眼所观察到的现实世界。

播放条件:HDR视频资源、一款支持HDR的显示器或者HDR电视、支持HDR视频的播放器软件即可实现播放。

目前HDR视频源较为有限,主要获取途径有:支持HDR的游戏(如古墓丽影崛起等),蓝光电影视频,Netflix(奈飞),YouTube,ITunes,Vimeo,爱奇艺(你没看错,爱奇艺是国内率先支持HDR视频的平台),优酷(优酷目前已有HDR模式),索尼富士的相机,NHK/BBC等电视台。
【视频HDR技术】
1)Dolby Vision(杜比视界)
本质上是一系列的画质增强技术,这里我们主要介绍它的HDR部分。杜比实验室的研究人员在探索HDR需要多少的动态范围时做了一项主观测试,有大约90%的受访者对0到10,000 nits(cd/m2)的亮度范围感到满意。所以杜比设计了一条理论最高亮度10,000 nits(cd/m2)的EOTF(Electro-Optical Transfer Function,电光转换函数)曲线PQ作为Dolby Vision标准的核心,但目前还没有显示设备能达到这一亮度所以目前Dolby Vision在内容标准上使用的实际最高亮度值为4,000 nits(cd/m2)。Dolby Vision支持最高到12 bits的位深和Rec.2020 的宽色域,并且拥有独立的SDR版本进行向下兼容。

2)HDR10和HDR10+
HDR10全称HDR10 Media Profile,在2015年8月27日由消费者技术协会(Consumer Technology Association,CTA)发布。HDR10采用Rec. 2020宽色域、10 bits位深、SMPTE ST 2084 (PQ)[4]作为传输曲线、使用SMPTE ST 2086色彩容积元数据(Mastering Display Color Volume)、最大帧平均亮度水平(Maximum Frame Average Light Level,MaxFALL) 和最大内容亮度水平(Maximum Content Light Level,MaxCLL),HDR10在数据编码上采用高效率视频编码(High Efficiency Video Coding,HEVC)。HDR10不支持向SDR兼容,因此无法在传统广播电视流上使用。可以说是一个免费授权的简化版Dolby Vision。

HDR10+于2017年4月20日由三星和亚马逊视频发布,是一种基于HDR10的标准。HDR10+同样采用Rec.2020宽色域和10 bits位深,和HDR10相比增加了动态元数据(SMPTE ST2094-40)。HDR10+的动态元数据是在逐个场景(scene-by-scene)或逐帧(frame-by-frame)的基础上更精确地进行色调和亮度级别的优化调整。

  1. HLG
    Hybrid Log-Gamma(HLG)是由BBC和NHK联合开发的HDR标准。它与标准动态范围(SDR)兼容,也支持Rec.2020宽色域和10bits位深。HLG定义了非线性光电传递函数(Optical-Electro Transfer Function,OETF),其中信号值的下半部分使用伽马曲线,信号值的上半部分使用对数曲线。HLG可以与SDR兼容,目前电视台的视频主要拍摄制作采用此格式。

小结:Dolby Vison、HDR10、HDR10+和HLG四种HDR标准之间的相关技术参数比较。

这么多种标准虽然有相互竞争的部分,在不同的领域还是有各自的倾向的。对于电影制片公司来说,制作一部院线电影的HDR版本就只有Dolby Vision可以选择了,目前只有Dolby Vision的标准里有支持院线的选项(作为杜比影院的一部分)。而在广播领域自然是HLG占有大量份额。在流媒体或者蓝光影片这样的家庭娱乐服务来说则是各有份额。
对于HDR技术来说,元数据就记录了电影画面中非常重要的信息,其中主要包括了色彩和亮度两大方面的信息,具体来看包括了影像的分辨率、色域范围、色度取样、色彩深度、码率、编码格式、帧率、画面比例、制作端显示设备的亮度等,其中有两个元数据是非常关键的,分别是MaxCLL内容的最高亮度等级和MaxFALL平均帧最高亮度等级。通过这些信息,我们就能让HDR显示设备正确处理HDR画面中的色彩与亮度细节,不会让这些重要的细节层次信息丢失。从功能上来说,HDR的元数据是来帮助显示设备以更好的方式来显示画面内容。从内容和作用范围上来看,可以分为静态元数据和动态元数据。

1.静态元数据:

一段视频中采用同样的元数据,去控制每一帧画面的色彩与细节,在帧之间并不会变化。优势当然是简单,而不足之处也同样明显,整部电影都采用同样的元数据来控制光影变化,可是电影之中的每一帧画面的动态范围并非一样,很容易会造成某些大动态场景的画面的暗部或高光细节出现丢失,比如说雪山、黑夜等场景。这也是早期HDR显示设备的HDR画面表现并不如意的主要原因,有些时候黑位很扎实,阳光感十足,有些时候画面容易出现过曝问题,高光层次丢失。

包括如下3大部分的内容。

第一部分是用于视频内容母版制作的显示器的色彩容积信息( 颜色空间、白点及最大最小亮度范围) ,这部分内容是在SMPTE ST 2086标准中定义的。

第二部分是Maximum content light level (MaxCLL),它表示的是整段视频所有帧里面,最亮的像素点的光亮度。

第三部分是Maximum Frame-Average Light Level (MaxFALL),它表示的是整段视频里面,最亮的帧的平均光亮度。

优势当然是简单

2.动态元数据:

就是允许为每一帧或者每一个场景切换指定元数据。以最大程度地优化HDR画面的亮度表现,尽量保证每一个场景的画面动态可以充分释放,同时还能保留丰富的暗部与高光细节层次。HDR10+和Dolby Vision都采用了动态元数据。

元数据:SMPTE ST 2086、SMPTE ST 2094、CEA-861.3

色调映射

色调映射,是在有限[动态范围]媒介上近似显示[高动态范围图像]的一项[计算机图形学]技术。打印结果、CRT 或者 LCD 显示器以及[投影仪]等都只有有限的动态范围。

本质上来讲,色调映射是要解决的问题是进行大幅度的[对比度]衰减将场景亮度变换到可以显示的范围,同时要保持图像细节与颜色等对于表现原始场景非常重要的信息。

有了元数据,要实现正确的HDR画面显示,还需要进行正确的色调映射才能实现。显示设备的色调映射,同样也分为静态映射与动态映射两种方式。

静态映射会根据HDR节目源中的静态元数据,对整部电影进行单一的色调映射,或者说采用单一的亮度曲线来处理高光滚落或高切点,对于显示设备的HDR处理性能要求不高,较为容易实现,所有的HDR设备都支持静态映射。

动态映射并不等于动态元数据,两者可以共同运行,而动态映射还可以单独运行。从运行效率和正确率的角度来说,结合动态元数据的动态映射是最为理想的。通过HDR10+和Dolby Vision中的动态元数据,显示设备并不需要配备高性能的处理器就能实现逐个场景甚至是逐帧的动态映射。这种方式属于预处理的动态映射技术。那么当遇到大量采用静态元数据的HDR10节目源的时候,想要进行动态映射处理,就只能依赖显示设备内置的处理系统了。需要注意的是,这种方式属于后处理的动态映射处理,并不能保证画面一定是正确的。也是因为这个原因,显示设备中的后处理动态映射处理功能,往往还会留给用户一定可调的空间,比如说预留高中低三个不同处理强度的设置档位,用户可以根据片源是偏向高光还是偏向暗部来自行选择。而前面所提到的动态元数据和动态映射相结合的预处理动态映射模式,如HDR10+就基本上只有开启或关闭的选项。

PSNR

是一个表示[信号]最大可能功率和影响它的表示精度的破坏性[噪声]功率的比值的工程术语。由于许多信号都有非常宽的[动态范围],峰值信噪比常用[对数][分贝(dB)]单位来表示。大于比率1:1(高于0分贝)表示信号多于噪声。
PSNR是最普遍,最广泛使用的评鉴[画质]的客观量测法,不过许多实验结果都显示,PSNR的分数无法和人眼看到的视觉品质完全一致,有可能PSNR较高者看起来反而比PSNR较低者差。这是因为人眼的视觉对于误差的敏感度并不是绝对的,其感知结果会受到许多因素的影响而产生变化(例如:人眼对空间频率较低的对比差异敏感度较高,人眼对[亮度对比]差异的敏感度较色度高,人眼对一个区域的感知结果会受到其周围邻近区域的影响)。

DOL HDR

传统多帧HDR
传统多帧HDR一般是使用non-overlapped模式,即每个图像采集的周期中,相机在下一个图像采集开始前,均要完成曝光/读出整个过程


image.png

Sony的行交织HDR称为DOL-HDR(Digital overlap)
OV的行交织称为staggered HDR
行交织HDR的效果如下:


image.png

行交织HDR一般是使用overlapped模式。即相机读出数据和下一帧曝光开始出现重叠的情况,在同一个时刻内,相机执行两个操作,导致在同样的单位时间内,在overlapped曝光模式下,可以采集到更多的图片,即相机的帧率更高。原理如下图:


image.png

在传统的多帧 HDR 里,每一帧都需要在上一帧完成读取后才能进行。CMOS 会先进行一次长曝光,然后从上到下完整读取出整个画面的数据,然后再开始中曝光,从上到下读一遍,最后以同样的方式完成短曝光。换言之两帧之间的时间间隔是曝光时间 + 传感器完整完成读取一帧的时间,在第一行像素被读出后,它需要等待其它行的像素被读取完才能开始中曝光。

如果我们能让 CMOS 的每一行像素完成读取后,立即开始下一次曝光,就可以省下等待其它像素完成读取的时间。我们让 CMOS 完成长曝光后,读取完第一行的同时,第一行像素几乎立即开始中曝光,而无需等待其它行的像素读取完成,而在这个时候,其它行也在进行着读取 - 下一次曝光的工作,每一行不同的曝光和读取交替进行,就像纺织里互相穿插的纱线一样,我们就把它称作行交织技术。两帧之间的读取间隔被缩短,物体运动带来的伪像得以显著改善。
简单讲就是:DOL HDR相比传统HDR读取完每一行所有像素然后开始曝光,完成后再分别进行长中短这种低效模式下,DOL HDR的长中短三次读取曝光是同时进行的(准同时)效率更高。

不同标准的色域对比

底是全色域:高度为亮度:三角形为色彩范围

相机/SDR/HDR的相对动态范围

image.png

OETF:光电转换函数

把光强转化为数字的函数,一般都是对数形态曲线(log)


image.png

对数形态曲线的功能是把线性的亮度-数值对应关系,转换成非线性的亮度-视觉感觉对应关系(线性表达用了一半的范围去表示一个亮度档位):


线性亮度表达与非线性表达,右侧对数据范围的运用更高效

EOTF:电光转换函数

把数字亮度转化为光线亮度,SDR一般是Gamma曲线(幂函数),HDR一般是HLG/PQ(ST2084)


image.png
PQ:感知量化曲线

杜比参考Barten Ramp研发的,HDR10和HDR10+也使用这个


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

推荐阅读更多精彩内容