代码整体结构与功能概述
这段 C++ 代码主要实现了两个图像特征提取算法,分别是局部方向模式(Local Directional Pattern,LDP)和多分块局部二值模式(Multi-Block Local Binary Pattern,Multi-Block LBP),并在读取一张灰度图像后,对其应用这两种算法提取特征,最后将原始图像以及提取特征后的结果进行可视化展示。
局部方向模式(LDP)相关代码解释
函数定义
cv::Mat calculateLDP(const cv::Mat& image) {
定义了一个名为calculateLDP
的函数,它接收一个cv::Mat
类型(OpenCV 中用于表示图像的数据结构)的常量引用参数image
,并返回一个同样是cv::Mat
类型的结果,用于表示经过 LDP 算法处理后的图像。
初始化输出图像
cv::Mat ldpImage = cv::Mat::zeros(image.size(), CV_8UC1);
创建一个与输入图像image
大小相同、数据类型为CV_8UC1
(8 位无符号单通道)的全零矩阵ldpImage
,用于存储后续计算得到的 LDP 特征图像。
计算水平和垂直方向的梯度
cv::Mat gradX, gradY;
cv::Sobel(image, gradX, CV_16S, 1, 0, 3);
cv::Sobel(image, gradY, CV_16S, 0, 1, 3);
使用 OpenCV 的Sobel
算子分别计算输入图像image
在水平(1, 0
表示在 x 方向求导,y 方向不求导)和垂直(0, 1
表示在 y 方向求导,x 方向不求导)方向上的梯度。计算结果gradX
和gradY
的数据类型被指定为CV_16S
(16 位有符号整数),以适应可能较大的梯度值,且使用了尺寸为 3 的 Sobel 核。
梯度数据类型转换
cv::Mat gradXf, gradYf;
gradX.convertTo(gradXf, CV_32F);
gradY.convertTo(gradYf, CV_32F);
将之前计算得到的 16 位有符号整数类型的梯度图像gradX
和gradY
转换为 32 位浮点数类型(CV_32F
)的gradXf
和gradYf
,这样做是为了后续更精确的数值计算,比如计算梯度幅值和方向时。
计算梯度幅值和方向
cv::Mat magnitude, angle;
cv::cartToPolar(gradXf, gradYf, magnitude, angle, true);
利用 OpenCV 的cartToPolar
函数,根据水平和垂直方向的梯度(gradXf
和gradYf
)计算出梯度幅值(存储在magnitude
中)和梯度方向(存储在angle
中),最后一个参数true
表示角度以弧度制表示。
方向量化相关设置
const int numDirections = 8;
const float angleStep = 2 * CV_PI / numDirections;
定义了方向量化的参数,这里将方向划分为 8 个区间,通过计算angleStep
来确定每个方向区间对应的弧度范围,以便后续将梯度方向量化到具体的区间中。
遍历图像像素计算 LDP
for (int y = 1; y < image.rows - 1; y++) {for (int x = 1; x < image.cols - 1; x++) {
通过两层嵌套的循环遍历图像中除边界像素(因为边界像素无法获取完整的邻域信息)外的所有像素点,准备计算每个像素的 LDP 值。
获取当前像素点的梯度方向并量化
float currentAngle = angle.at<float>(y, x);
int quantizedDirection = static_cast<int>(currentAngle / angleStep);
if (quantizedDirection >= numDirections) {quantizedDirection = 0;
}
首先获取当前像素点(坐标为(x, y)
)的梯度方向值,然后按照之前设定的方向量化步长angleStep
将其量化到对应的方向区间,得到quantizedDirection
,如果量化后的方向编号超出了设定的方向数量范围,则将其重置为 0。
设置当前像素的 LDP 值
ldpImage.at<uchar>(y, x) = (1 << quantizedDirection);
根据量化后的方向,通过位运算将对应二进制位设置为 1,来初始化当前像素的 LDP 值,这样每个像素的 LDP 值初始就反映了自身的梯度方向信息。
考虑相邻像素的方向信息
int neighborOffsets[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
for (int i = 0; i < 4; i++) {// 获取相邻像素坐标int neighborY = y + neighborOffsets[i][0];int neighborX = x + neighborOffsets[i][1];// 判断相邻像素坐标是否合法if (neighborY >= 0 && neighborY < image.rows && neighborX >= 0 && neighborX < image.cols) {// 获取相邻像素的量化方向float neighborAngle = angle.at<float>(neighborY, neighborX);int neighborQuantizedDirection = static_cast<int>(neighborAngle / angleStep);if (neighborQuantizedDirection >= numDirections) {neighborQuantizedDirection = 0;}// 将相邻像素的方向信息合并到当前像素的LDP值中ldpImage.at<uchar>(y, x) |= (1 << neighborQuantizedDirection);}
}
定义了一个包含上下左右四个相邻像素相对坐标偏移量的数组neighborOffsets
,然后通过循环遍历这四个相邻像素。对于合法坐标的相邻像素(在图像范围内),获取其梯度方向并量化,再通过位运算将其方向信息合并到当前像素的 LDP 值中,使得最终的 LDP 值不仅包含自身的梯度方向,还综合了周边像素的方向特征。
返回 LDP 图像
return ldpImage;
在完成对所有像素的 LDP 值计算后,将计算得到的 LDP 特征图像ldpImage
作为函数结果返回。
多分块局部二值模式(Multi-Block LBP)相关代码解释
函数定义
cv::Mat calculateMultiBlockLBP(const cv::Mat& image, int blockSize) {
定义了名为calculateMultiBlockLBP
的函数,接收输入图像image
和表示分块大小的参数blockSize
,返回一个cv::Mat
类型的结果,即经过多分块 LBP 算法处理后的图像。
初始化输出图像
cv::Mat lbpImage = cv::Mat::zeros(image.size(), CV_8UC1);
同样创建一个与输入图像大小相同、数据类型为CV_8UC1
的全零矩阵lbpImage
,用于存储最终的多分块 LBP 特征图像。
计算分块数量
int numBlocksX = image.cols / blockSize;
int numBlocksY = image.rows / blockSize;
根据输入图像的尺寸和设定的分块大小blockSize
,分别计算在水平和垂直方向上划分的块的数量,用于后续遍历分块的循环。
遍历图像分块及分块内像素
for (int by = 0; by < numBlocksY; by++) {for (int bx = 0; bx < numBlocksX; bx++) {for (int y = by * blockSize; y < (by + 1) * blockSize; y++) {for (int x = bx * blockSize; x < (bx + 1) * blockSize; x++) {
通过四层嵌套循环实现对图像的分块以及每个分块内像素的遍历。外层两层循环控制分块的坐标,内层两层循环则遍历每个分块内的具体像素。
获取中心像素值并初始化 LBP 码
uchar centerPixel = image.at<uchar>(y, x);
uchar lbpCode = 0;
对于当前遍历到的像素(坐标为(x, y)
),获取其作为中心像素的值,同时初始化一个变量lbpCode
用于存储该像素对应的 LBP 码,初始值为 0。
遍历当前块内的相邻像素计算 LBP 码
for (int dy = -1; dy <= 1; dy++) {for (int dx = -1; dx <= 1; dx++) {if (dx == 0 && dy == 0) continue;int neighborY = y + dy;int neighborX = x + dx;if (neighborY < 0 || neighborY >= image.rows || neighborX < 0 || neighborX >= image.cols) {continue;}uchar neighborPixel = image.at<uchar>(neighborY, neighborX);lbpCode <<= 1;if (neighborPixel >= centerPixel) {lbpCode |= 1;}}
}
通过两层嵌套循环遍历当前块内以当前像素为中心的 3x3 邻域(排除中心像素本身),获取每个相邻像素的值neighborPixel
。然后按照 LBP 算法的规则,如果相邻像素值大于等于中心像素值,则将lbpCode
对应的二进制位设置为 1(通过左移并进行位或运算实现),这样就逐步构建出了当前像素的 LBP 码。
设置当前像素的 LBP 值
lbpImage.at<uchar>(y, x) = lbpCode;
将计算得到的当前像素的 LBP 码赋值给lbpImage
中对应的像素位置,完成该像素的多分块 LBP 值的设置。
返回多分块 LBP 图像
return lbpImage;
在遍历完所有分块及分块内像素后,将包含完整多分块 LBP 特征的图像lbpImage
作为函数结果返回。
主函数(main
)相关代码解释
图像读取
cv::Mat image = cv::imread("C:\\Users\\tangzy\\Desktop\\测试图像\\16.jpg", cv::IMREAD_GRAYSCALE);
if (image.empty()) {std::cout << "无法读取图像!" << std::endl;return -1;
}
使用 OpenCV 的imread
函数尝试从指定路径读取一张图像,并指定以灰度模式(cv::IMREAD_GRAYSCALE
)读取。如果读取失败(图像为空),则输出提示信息并返回错误代码-1
终止程序。
计算 LDP 和多分块 LBP 特征
cv::Mat ldpResult = calculateLDP(image);
int blockSize = 16;
cv::Mat multiBlockLBPResult = calculateMultiBlockLBP(image, blockSize);
分别调用calculateLDP
和calculateMultiBlockLBP
函数对读取到的图像image
进行特征提取,得到 LDP 特征图像ldpResult
以及块大小为 16 的多分块 LBP 特征图像multiBlockLBPResult
。
可视化结果
cv::imshow("原始图像", image);
cv::imshow("LDP结果", ldpResult);
cv::imshow("多分块LBP结果", multiBlockLBPResult);
cv::waitKey(0);
使用 OpenCV 的imshow
函数分别将原始图像、LDP 特征图像和多分块 LBP 特征图像显示在不同的窗口中,窗口标题分别为对应的名称。然后通过waitKey(0)
函数暂停程序,等待用户按下任意键后关闭窗口,结束程序。
返回程序正常结束代码
return 0;
主函数最后返回 0,表示程序正常结束。
应用场景描述
人脸识别领域
-
LDP 应用场景:
在人脸识别中,人脸图像具有丰富的纹理信息,不同人的面部纹理在方向上存在差异。例如眼睛、鼻子、嘴巴等部位的轮廓方向特点不同。LDP 算法通过捕捉图像局部的梯度方向信息并综合相邻像素的方向,可以很好地刻画这些面部纹理特征。通过对大量人脸图像训练样本提取 LDP 特征,然后使用分类算法(如支持向量机、深度学习分类器等),可以构建人脸识别模型,用于识别不同的人脸个体。比如在门禁系统中,利用摄像头获取人脸图像后提取 LDP 特征与人脸数据库中已注册人员的特征进行比对,从而判断是否为授权人员,实现人员的身份验证。 -
Multi-Block LBP 应用场景:
多分块 LBP 同样对纹理信息敏感,它在人脸识别中的优势在于可以从不同尺度(由分块大小决定)上捕捉人脸的局部纹理变化。对于人脸这种既有宏观轮廓特征(如脸的整体形状等通过较大分块体现)又有微观纹理细节(如皮肤的毛孔等通过较小分块体现)的图像来说,多分块 LBP 能够更全面地提取特征。例如在刑侦领域,对于监控视频中模糊或者部分遮挡的人脸图像,通过提取多分块 LBP 特征,可以增强对人脸关键特征的描述能力,辅助警方进行嫌疑人的身份排查和比对,提高人脸识别的准确率和鲁棒性。
医学图像分析领域
-
LDP 应用场景:
在医学影像(如 X 光片、CT 扫描图像、MRI 图像等)中,不同的组织结构往往具有特定的纹理走向和方向特征。以 X 光片中的骨骼为例,骨骼的纹理方向在不同部位、不同病变状态下可能会有变化。利用 LDP 算法可以提取出骨骼纹理的方向信息,帮助医生判断骨骼是否存在骨折、骨质疏松等病变情况。对于肿瘤的检测也是如此,正常组织和肿瘤组织在纹理方向上可能存在差异,通过对大量医学影像样本提取 LDP 特征并结合机器学习算法进行分类,可以辅助医生进行疾病的早期诊断和病情评估。 -
Multi-Block LBP 应用场景:
医学图像往往分辨率和复杂度较高,多分块 LBP 能够从不同层次挖掘图像的纹理细节。比如在分析肝脏的 CT 图像时,不同大小的分块可以分别捕捉肝脏整体的轮廓纹理特征(大分块)以及肝脏内部血管、病变区域等微观纹理变化(小分块)。医生可以通过观察多分块 LBP 特征图像直观地发现肝脏是否存在囊肿、纤维化等病变,而且可以基于提取的特征进行定量分析,结合计算机辅助诊断系统更准确地评估病情严重程度,制定合理的治疗方案。
纹理图像分类领域
-
LDP 应用场景:
在工业产品表面纹理检测、天然材料纹理分类等场景中,LDP 可以区分不同类型的纹理。例如在纺织品行业,不同材质、不同编织工艺的布料表面纹理方向不同,通过对布料样本图像提取 LDP 特征,然后利用分类模型,可以快速准确地对布料的纹理进行分类,实现自动化的质量检测,判断布料是否符合生产标准等。对于木材、石材等天然材料的纹理分类也同样适用,有助于资源的分类管理和加工利用。 -
Multi-Block LBP 应用场景:
多分块 LBP 在纹理图像分类中更具优势,因为它可以同时兼顾纹理的宏观和微观特征。比如在卫星遥感图像中,对不同地貌(如森林、沙漠、农田等)的纹理进行分类时,大分块可以捕捉到地貌整体的纹理布局特征,小分块能进一步提取到植被的细节、土壤颗粒等微观纹理信息。通过提取多分块 LBP 特征并进行分类,可以更精准地识别不同的地貌类型,为地理信息系统、农业监测、环境研究等领域提供有力的数据支持。
图像检索领域
-
LDP 应用场景:
当用户希望从庞大的图像数据库中检索出具有相似纹理方向特征的图像时,LDP 特征就可以发挥作用。例如在一个艺术图片数据库中,用户输入一张具有特定纹理风格(如某种笔触方向的绘画作品)的图片,系统对数据库中所有图片提取 LDP 特征,然后通过特征匹配算法(如计算特征向量的距离等),找出与输入图片 LDP 特征相似度较高的图片返回给用户,实现基于纹理方向特征的图像检索功能。 -
Multi-Block LBP 应用场景:
多分块 LBP 在图像检索方面能够提供更丰富的纹理特征描述。比如在商标图像检索中,商标图像往往包含多种尺度的纹理元素,通过提取多分块 LBP 特征,可以更全面地刻画商标的纹理特征。用户上传一个商标图像进行检索时,系统利用多分块 LBP 特征在商标图像数据库中查找相似的商标,可应用于商标侵权检测、品牌管理等场景,提高图像检索的准确性和召回率。
视频监控领域
虚拟现实与增强现实领域
总之,局部方向模式(LDP)和多分块局部二值模式(Multi-Block LBP)这两种图像特征提取算法在众多领域都有着广泛且重要的应用价值,它们从不同角度挖掘图像的纹理特征,为解决各种实际问题提供了有效的手段,并且随着相关技术的不断发展,其应用场景还将不断拓展和深化。
-
LDP 应用场景:
在视频监控画面中,对运动目标(如行人、车辆等)的识别和跟踪可以借助 LDP 特征。以行人识别为例,行人的衣着纹理、行走姿态等会在图像中体现出不同的方向特征,通过实时提取监控画面中行人的 LDP 特征,可以在复杂背景下更好地将行人从背景中区分出来,并且在后续帧中根据 LDP 特征的相似性进行行人的跟踪,为智能安防系统提供关键的目标信息,辅助分析人员对监控场景中异常行为等情况进行及时判断。 -
Multi-Block LBP 应用场景:
对于监控画面中不同物体的分类和识别,多分块 LBP 能发挥重要作用。比如区分不同类型的车辆(轿车、卡车、客车等),车辆的外观纹理在不同尺度下有各自特点,大分块可以体现车身整体的轮廓纹理差异,小分块能捕捉到诸如车牌区域、车身装饰线条等细节纹理。通过提取多分块 LBP 特征并配合合适的分类器,就能实现对监控画面中车辆类型的准确识别,进一步提升视频监控在交通管理、安防布控等方面的智能化水平。而且在监控场景中目标可能会出现部分遮挡、光照变化等情况,多分块 LBP 特征相对更具鲁棒性,依然能够提取到有效的纹理特征用于目标的持续识别和分析。
生物特征识别领域(除人脸识别外)
- LDP 应用场景:
在指纹识别方面,指纹的纹路本身有着独特的方向走势,存在着如箕型纹、斗型纹等不同类型,其脊线和谷线的方向变化是区分不同指纹的关键因素之一。LDP 算法能够精准地提取指纹图像局部的方向信息,将这些方向特征组合起来形成指纹的特征表示。在指纹识别系统中,无论是用于刑侦破案时与数据库中的指纹样本比对,还是日常的门禁、设备解锁等民用指纹识别场景,基于 LDP 特征都可以更准确地判断两枚指纹是否来自同一手指,提高识别的准确率和可靠性。 -
在虹膜识别领域,虹膜的纹理呈现出复杂且有规律的方向分布,其纹理细节包含了丰富的个体差异信息。LDP 可以提取出虹膜纹理不同部位的方向特征,构建出具有区分性的虹膜特征向量。然后通过匹配算法与已注册的虹膜特征进行对比,应用于高安全级别的身份验证场景,比如机场安检、重要场所的人员准入等,确保只有授权人员能够进入相应区域。
- Multi-Block LBP 应用场景:
对于掌纹识别,掌纹包含了主线、皱纹、细小纹理等多种纹理信息,且这些纹理在不同尺度下都有着重要的识别价值。多分块 LBP 通过不同大小的分块可以分别提取掌纹的宏观纹理布局(如主要纹路走向)以及微观纹理细节(如皱纹的分布特点),综合这些特征形成更全面、更具区分性的掌纹特征描述。在刑侦、边境管控等需要严格身份核实的场景中,利用多分块 LBP 提取的掌纹特征可以有效鉴别人员身份,辅助打击违法犯罪行为,保障公共安全。 -
在静脉识别中,手部或其他部位的静脉图像有着独特的纹理形态和分布特点,不同个体的静脉纹理在粗细、走向以及分支情况等方面都存在差异。多分块 LBP 可以从多个尺度分析静脉图像的纹理,无论是静脉的主干纹理还是周围细小分支的纹理特征都能被捕捉到,从而生成更准确的静脉特征表示,用于诸如金融机构的高安全级别身份认证、高端保密场所的人员准入等场景,防止身份冒用等安全问题。
工业检测领域
- LDP 应用场景:
在电子元器件表面质量检测中,电子芯片、电路板等产品的表面有着精细的线路和纹理结构,其线路的走向、焊点周围纹理等方向特征对于判断产品质量至关重要。LDP 算法可以提取这些表面纹理的方向信息,检测是否存在线路断裂、短路(通过纹理方向的异常变化体现)、焊点缺陷等问题。在自动化生产线上,实时提取电子元器件图像的 LDP 特征,并与合格产品的标准 LDP 特征进行对比,能够快速筛选出次品,提高生产效率和产品质量。 -
对于机械零部件的表面磨损检测,随着零部件的使用,其表面纹理会因为磨损而发生方向和形态的改变。例如发动机的活塞、曲轴等关键部件,通过对其表面图像提取 LDP 特征,对比新部件的标准纹理方向特征,能够及时发现磨损程度,预测零部件的剩余使用寿命,以便合理安排设备维护和更换计划,保障机械设备的正常运行,避免因零部件故障导致的生产事故。
- Multi-Block LBP 应用场景:
在陶瓷、玻璃等易碎材料的成品检测中,这些材料表面可能存在微小的裂纹、气泡等缺陷,这些缺陷会改变材料表面的纹理特征。多分块 LBP 能够从不同尺度捕捉到纹理的变化,大分块可以发现较大范围的纹理异常(可能对应较大面积的质量问题区域),小分块则能精准定位到微小的缺陷点。在生产过程中,利用多分块 LBP 对产品图像进行特征提取和分析,有助于严格把控产品质量,减少不合格产品流入市场,提升企业的市场竞争力。 -
在塑料制品的外观质量检测中,塑料制品表面可能出现划痕、脱模不良导致的纹理不均等问题。多分块 LBP 可以全面分析其表面纹理,不同分块大小对应不同层次的纹理观察,通过提取的特征与标准产品特征对比,实现对塑料制品外观质量的自动化评估,满足大批量生产中快速、准确检测的需求,提高生产效益。
农业领域
- LDP 应用场景:
在农作物病虫害监测方面,病虫害侵袭往往会导致农作物叶片、茎秆等部位的纹理方向发生变化。例如,遭受虫害的叶片可能会出现被啃食的痕迹,使得原本平滑的纹理出现不规则的方向改变;患有病害的植株部分区域的纹理也会因为病变而与健康部位不同。通过对农田中农作物图像提取 LDP 特征,结合机器学习算法建立病虫害识别模型,可以及时准确地发现病虫害情况,帮助农民尽早采取防治措施,减少农作物的损失,保障粮食产量和农产品质量。 -
在果实品质检测中,不同品种的果实表面纹理方向有一定差异,而且同一品种的优质果实和劣质果实(如存在表面损伤、发育不良等情况)在纹理上也会有体现。例如苹果表面的果皮纹理,利用 LDP 特征可以对果实进行分类和品质评估,区分出符合市场标准的高品质果实和需要进一步筛选的次品,有利于农产品的分级销售和加工利用。
- Multi-Block LBP 应用场景:
对于农田土壤质地分析,土壤表面的纹理从宏观上反映了土壤的颗粒大小分布、平整度等情况,从微观上体现了土壤中有机物含量、微生物活动等留下的痕迹。多分块 LBP 通过不同尺度的分块可以同时提取这些不同层次的土壤纹理信息,帮助农业科研人员和农民更好地了解土壤状况,为合理施肥、灌溉以及选择适宜的农作物种植品种等提供科学依据,实现精准农业管理,提高土地的产出效率。 -
在畜牧养殖中,动物的皮毛纹理也可以作为健康和品种识别的依据。例如不同品种的羊,其羊毛纹理有差异,而且羊在患病或营养不良时,皮毛的光泽和纹理方向也会有所改变。通过提取多分块 LBP 特征,可以对羊群进行品种分类以及健康状况监测,辅助养殖户科学养殖,及时发现和处理动物健康问题,提高养殖效益。
文物保护与考古领域
-
LDP 应用场景:
在对古代壁画、雕刻等文物的修复和研究中,文物表面的纹理方向承载着重要的历史信息和艺术风格特征。例如古代壁画上人物服饰、建筑装饰等部分的纹理走向反映了当时的绘画技法和审美观念。LDP 算法可以提取这些纹理方向信息,帮助文物修复专家更准确地还原受损部分的纹理,使其与周边原有纹理相匹配,实现更精细、更符合历史原貌的修复工作。同时在考古研究中,通过对比不同遗址出土文物的 LDP 特征,可以分析古代不同地区、不同时期的工艺传承和文化交流情况,为考古学的断代、文化溯源等研究提供有力的图像纹理方面的证据。 -
Multi-Block LBP 应用场景:
对于古代陶瓷、青铜器等文物,其表面有着丰富的纹理细节,包括制作时留下的纹路、岁月侵蚀产生的痕迹等。多分块 LBP 能够从不同尺度分析这些纹理,大分块可以体现整体的造型纹理风格,小分块则能捕捉到如釉面的微小变化、青铜器表面的锈蚀纹理等细节特征。在文物鉴定中,提取文物图像的多分块 LBP 特征并与已知年代、产地的标准文物特征进行比对,可以辅助判断文物的真伪、年代以及可能的出土地点等信息,防止文物造假现象,保护文化遗产的真实性和完整性。 - LDP 应用场景:
在虚拟现实(VR)场景建模中,对于虚拟环境中的各种物体表面纹理模拟,LDP 可以用来提取现实世界中对应物体的纹理方向特征,使虚拟物体的纹理更加逼真,增强用户在虚拟环境中的沉浸感。例如在创建一个古代城堡的 VR 场景时,城堡墙壁、地面等建筑元素的纹理方向通过 LDP 算法从真实的古建筑图片中提取,然后应用到虚拟模型上,让用户仿佛身临其境般感受到城堡的真实质感。 - Multi-Block LBP 应用场景:
在 VR 游戏开发中,游戏场景中的地形、建筑等元素需要丰富多样且逼真的纹理表现。多分块 LBP 可以从不同尺度对现实世界中的相似场景进行纹理特征提取,然后应用到虚拟游戏场景中。大分块用于构建地形、大型建筑的整体外观纹理,小分块则用于细化细节,如岩石的纹理、墙壁上的装饰纹理等,让游戏场景更加细腻、生动,吸引玩家沉浸其中。 - 编辑