基于 OpenCV 与 Java 两个语言版本实现获取某一图片特定区域的颜色对比度
Posted 程序员洲洲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于 OpenCV 与 Java 两个语言版本实现获取某一图片特定区域的颜色对比度相关的知识,希望对你有一定的参考价值。
本文目录
一、什么是对比度
对比度是指图像中不同区域之间的明暗差异程度,它是图像质量中的重要指标之一。除了颜色对比度之外,常见的对比度包括:
1、亮度对比度(Brightness Contrast):指图像中不同区域之间的亮度差异程度。计算方法可以使用像素灰度值的标准差或方差来描述。
2、方向对比度(Orientation Contrast):指图像中不同方向区域之间的差异程度。例如,某些图像中有明显的纹理或线条方向,可以通过计算不同方向的图像灰度值差异来描述图像的方向对比度。
3、空间对比度(Spatial Contrast):指图像中不同空间区域之间的差异程度。例如,在自然风光图像中,不同区域的颜色和纹理通常具有空间分布特性,可以通过计算局部对比度来描述这种特性。
4、颜色对比度是指图像中不同颜色区域之间的明显差异程度。在计算机视觉和图像处理中,颜色对比度通常用于描述彩色图像中不同区域之间的颜色差异,可以通过计算颜色空间中的颜色距离来度量。
这些对比度指标通常可以用于图像质量评价、图像增强和图像分割等领域。其中,颜色对比度和亮度对比度是最常用的对比度指标。
二、什么是颜色直方图
颜色直方图是一种描述图像中颜色分布情况的统计方法。它可以将图像中每个像素的颜色按照一定的规则进行分组,并计算出每个颜色组中包含的像素数量,最终得到一个表示颜色分布的直方图。
通常情况下,颜色直方图是针对彩色图像中的每个颜色通道(如红色、绿色、蓝色)分别计算的,因此可以得到三个独立的直方图。这些直方图可以用来描述图像中的颜色分布情况,比如哪些颜色比较常见、哪些颜色比较稀少等等。
颜色直方图在计算机视觉领域有广泛的应用,例如图像检索、目标识别、图像分割、图像增强等等。
三、如何通过RGB计算颜色对比度
计算RGB图像的颜色对比度,可以使用颜色直方图的方法。以下是基于RGB颜色空间计算颜色对比度的方法:
1、将RGB图像转换为灰度图像。
2、计算灰度图像的颜色直方图。
3、将颜色直方图进行归一化,即将所有的像素值缩放到0-1之间。
4、计算颜色对比度,通常使用方差(Variance)的计算方法,其公式如下:
其中, N N N表示颜色直方图的总大小, p i p_i pi表示第 i i i个像素的归一化值, p ˉ \\barp pˉ表示所有像素的平均归一化值。
这样就可以通过RGB颜色空间计算颜色对比度了。需要注意的是,RGB颜色空间的颜色对比度计算方法只适用于灰度图像,如果需要计算彩色图像的颜色对比度,则需要先将图像转换到HSV或Lab颜色空间,再进行计算。
什么是HSV、Lab颜色空间
HSV和Lab颜色空间是两种常用的颜色模型,它们分别描述了颜色的色相、饱和度、亮度和颜色的明暗、红绿蓝等属性,可以用于图像处理和计算机视觉等领域。
HSV颜色空间(Hue, Saturation, Value)是一种基于人类视觉感知的颜色模型,其中色相(Hue)表示颜色的色调,取值范围为0-360度;饱和度(Saturation)表示颜色的鲜艳程度,取值范围为0-1;亮度(Value)表示颜色的明暗程度,取值范围为0~1。HSV颜色空间可以通过RGB颜色空间转换得到,其优点是可以方便地调整图像的颜色和亮度,例如可以通过改变亮度值来实现图像的调整和增强。
Lab颜色空间(Lab*)是一种用于描述颜色的三维空间,其中L表示明度(Lightness),取值范围为0100;a表示从红色到绿色的颜色值,取值范围为-128-127;b表示从黄色到蓝色的颜色值,取值范围为-128~127。Lab颜色空间是一种与设备无关的颜色模型,可以描述出更广泛的颜色范围,适用于图像处理、颜色匹配和图像检索等领域。在计算Lab颜色空间中颜色距离时,通常使用CIEDE2000色差公式计算,可以更好地匹配人眼的视觉感知。
HSV和Lab颜色空间在不同的领域中有不同的应用,例如在计算机视觉中,可以使用HSV颜色空间进行目标检测和跟踪,使用Lab颜色空间进行图像匹配和检索。
GB、HSV和Lab颜色空间都是用于描述彩色图像的颜色模型,而灰度图像则是一种仅包含亮度信息的图像。
在灰度图像中,每个像素仅包含一个灰度值,表示该像素的亮度信息,通常取值范围为0~255,其中0表示黑色,255表示白色,其它数值表示不同亮度级别的灰色。因此,灰度图像中的每个像素可以用一个单独的字节表示,所以灰度图像具有较小的存储空间和计算成本。
相比之下,彩色图像需要存储RGB、HSV或Lab三个通道中的每个像素值,因此需要更大的存储空间和计算成本。但是,彩色图像包含了更丰富的颜色信息,可以更好地反映图像的色彩和亮度变化。在某些领域,如计算机视觉、图像处理和医学图像等,彩色图像比灰度图像更适合用于分析和处理。
总之,灰度图像只包含亮度信息,而彩色图像则包含颜色和亮度信息,彩色图像可以更好地反映图像的色彩和亮度变化,但需要更大的存储空间和计算成本。
四、OpenCV代码
import cv2
import numpy as np
def get_contrast(img, x1, y1, x2, y2):
# 获取选定区域的颜色直方图
roi = img[y1:y2, x1:x2]
hist = cv2.calcHist([roi], [0], None, [256], [0, 256])
# 计算颜色对比度
hist_norm = cv2.normalize(hist, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
contrast = np.sum((hist_norm - np.mean(hist_norm)) ** 2) / len(hist_norm)
return contrast
# 读取图片
img = cv2.imread("image.jpg")
# 显示图片,用户可以用鼠标在图片上选择区域
cv2.imshow("image", img)
rect = cv2.selectROI("image", img, False)
cv2.destroyAllWindows()
# 计算选定区域的颜色对比度
x1, y1, w, h = rect
x2, y2 = x1 + w, y1 + h
contrast = get_contrast(img, x1, y1, x2, y2)
# 输出结果
print("选定区域的颜色对比度为:", contrast)
这个程序首先使用cv2.imread()函数读取输入的图片,然后使用cv2.selectROI()函数让用户在图片上选择感兴趣的区域。选定区域后,程序调用get_contrast()函数计算该区域的颜色对比度。最后,程序输出结果。get_contrast()函数中,我们使用cv2.calcHist()函数计算选定区域的颜色直方图,然后计算颜色对比度。
五、Java代码
5.1 平滑处理
平滑化处理,也称为平滑滤波,是一种常见的图像处理技术,主要用于减少图像中的噪声、平滑图像、模糊化图像等。该方法的基本思路是通过对图像中每个像素周围的邻域像素进行加权平均来降低图像中的高频成分,从而使图像变得更加平滑、连续,减少噪声对图像的影响。
在平滑化处理中,常用的方法包括均值滤波、高斯滤波、中值滤波等。这些方法的具体实现方式不同,但都能有效地减少图像中的噪声,并使图像变得更加平滑,从而方便后续的图像处理操作。
5.2 完整代码
try
File file = new File("image.jpg");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
int minx = image.getMinX();
int miny = image.getMinY();
// 首先读入图片,然后指定区域。
System.out.println("width=" + width + ", height=" + height + ".");
System.out.println("minx=" + minx + ", miny=" + miny + ".");
for (int i = minx; i < width; i += 5)
flag = 1;
for (int j = miny; j < height; j += 1)
flag = 1;
int pixel = image.getRGB(i, j);
int r1 = (pixel & 0xff0000) >> 16;
int g1 = (pixel & 0xff00) >> 8;
int b1 = (pixel & 0xff);
// System.out.println(i+"=i,"+j+"=j,("+rgb1[0]+","+rgb1[1]+","+rgb1[2]+")");
// 获取每个像素点的RGB。
catch (IOException e)
e.printStackTrace();
public double luminanace(int r, int g, int b)
double[] a = r / 255.0, g / 255.0, b / 255.0;
for (int i = 0; i < a.length; i++)
a[i] = a[i] <= 0.03928 ? a[i] / 12.92 : Math.pow((a[i] + 0.055) / 1.055, 2.4);
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
public double getContrast(BufferedImage image, int x1, int y1, int x2, int y2)
int pixel1 = image.getRGB(x1, y1);
int r1 = (pixel1 & 0xff0000) >> 16;
int g1 = (pixel1 & 0xff00) >> 8;
int b1 = (pixel1 & 0xff);
int pixel2 = image.getRGB(x2, y2);
int r2 = (pixel2 & 0xff0000) >> 16;
int g2 = (pixel2 & 0xff00) >> 8;
int b2 = (pixel2 & 0xff);
double lum1 = luminanace(r1, g1, b1);
double lum2 = luminanace(r2, g2, b2);
double brightest = Math.max(lum1, lum2);
double darkest = Math.min(lum1, lum2);
return (brightest + 0.05) / (darkest + 0.05);
这段代码是计算颜色对比度的公式。其中,luminance(r,g,b)是将RGB颜色空间下的颜色值转换为亮度值,采用的是sRGB彩色空间中的标准转换公式。对于每个颜色通道的值r、g、b,首先将它们归一化到0~1的范围内,然后根据其大小关系,采用不同的公式进行转换。最终将R、G、B三个通道的亮度值按一定的比例相加,得到一个灰度值,表示该像素的亮度信息。
接下来,代码中使用了亮度值计算颜色对比度的公式,即将两个像素的亮度值进行比较,得到最亮的和最暗的像素的亮度值,并计算它们的比值,用来表示颜色对比度的强弱程度。其中,为了防止计算过程中出现0的情况,加上了一个较小的常数0.05作为平滑处理。
OpenCV+OpenVINO实现人脸Landmarks实时检测
关注获取更多计算机视觉与深度学习知识
缘由
自从OpenCV3.3版本引入深度神经网络(DNN)模块之后,OpenCV对DNN模块支持最好的表现之一就是开始支持基于深度学习人脸检测,OpenCV本身提供了两个模型分别是基于Caffe与Tensorflow的,Caffe版本的模型是半精度16位的,tensorflow版本的模型是8位量化的。同时OpenCV通过与OpenVINO IE模型集成实现了底层硬件对对象检测、图像分割、图像分类等常见模型加速推理支持。OpenVINO框架本身提供直接快速开发应用原型的模型库,对很多常见视觉任务都可以做到快速演示支持。说起人脸的Lankmarks提取,最早的OpenCV跟DLib支持的方式都是基于AAM算法实现的68个人脸特征点的拟合模型,另外OpenCV中支持landmark的人脸检测会先加载一个很大的模型文件,然后速度感人,觉得还有很大的改进空间。好处是OpenCV自己提供了一个训练工具,可以自己训练模型。常见的MTCNN同时实现了人脸检测跟landmarks检测,但是只支持5点检测。而OpenVINO自带的Landmark检测模型基于自定义的卷积神经网络实现,取35个人脸各部位关键点。
模型文件
人脸检测模型
使用OpenCV DNN模块人脸检测的tensorflow量化8位模型
opencv_face_detector_uint8.pb权重文件
opencv_face_detector.pbtxt配置文件
OpenCV3.3以上版本支持
Landmarks检测
模型名称:facial-landmarks-35-adas-0002
支持35点分布表示出左眼、右眼、鼻子、嘴巴、左侧眉毛、右侧眉毛、人脸轮廓。模型的输入格式为:
BCHW = [1x3x60x60]
模型的输出数据为:[1x70]大小的浮点数组、对应到35个点x、y的坐标。
输出层名称:align_fc3
程序演示
首先加载模型文件
// 加载LANDMARK
Net mkNet = readNetFromModelOptimizer(landmark_xml, landmark_bin);
mkNet.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
mkNet.setPreferableTarget(DNN_TARGET_CPU);
// 加载网络
Net net = cv::dnn::readNetFromTensorflow(tensorflowWeightFile, tensorflowConfigFile);
net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
net.setPreferableTarget(DNN_TARGET_CPU);
使用网络实现人脸检测与landmark检测
首先读取视频的每一帧,检测人脸,得到的人脸区域转换位blob对象之后,再调用landmark检测模型forward方法得到输出结果,实现的代码如下:
Mat frame;
while (true) {
bool ret = cap.read(frame);
if (!ret) {
break;
}
// flip(frame, frame, 1);
cv::Mat inputBlob = cv::dnn::blobFromImage(frame, 1.0, cv::Size(300, 300),
Scalar(104.0, 177.0, 123.0), false, false);
net.setInput(inputBlob, "data");
cv::Mat detection = net.forward("detection_out");
cv::Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
for (int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at<float>(i, 2);
if (confidence > 0.5)
{
int x1 = static_cast<int>(detectionMat.at<float>(i, 3) * w);
int y1 = static_cast<int>(detectionMat.at<float>(i, 4) * h);
int x2 = static_cast<int>(detectionMat.at<float>(i, 5) * w);
int y2 = static_cast<int>(detectionMat.at<float>(i, 6) * h);
Mat roi = frame(Range(y1, y2), Range(x1, x2));
Mat blob = blobFromImage(roi, 1.0, Size(60, 60), Scalar(), false, false);
mkNet.setInput(blob);
Mat landmark_data = mkNet.forward();
// printf("rows: %d \n, cols : %d \n", landmark_data.rows, landmark_data.cols);
for (int i = 0; i < landmark_data.cols; i += 2) {
float x = landmark_data.at<float>(0, i)*roi.cols+x1;
float y = landmark_data.at<float>(0, i + 1)*roi.rows+y1;
// mkList.push_back(Point(x, y));
circle(frame, Point(x, y), 2, Scalar(0, 0, 255), 2, 8, 0);
}
cv::rectangle(frame, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0), 2, 8);
}
}
imshow("Face-Detection Demo", frame);
char c = waitKey(1);
if (c == 27) {
break;
}
}
运行结果如下:
至于速度,我只能告诉你很实时,我是i7 CPU。
想尝试下载与使用OpenVINO直接从下面链接即可开始:
https://software.intel.com/en-us/openvino-toolkit/choose-download?innovator=CONT-0026250
推荐阅读
以上是关于基于 OpenCV 与 Java 两个语言版本实现获取某一图片特定区域的颜色对比度的主要内容,如果未能解决你的问题,请参考以下文章
OpenCV+OpenVINO实现人脸Landmarks实时检测
OpenCV+OpenVINO实现人脸Landmarks实时检测