在本教程中,我们将学习计算机视觉中常用的颜色空间,并使用它进行基于颜色的分割。我们还将共享c++和Python的演示代码。
我们在许多计算机视觉应用中都遇到了这个问题,包括肤色检测、交通灯识别等基于颜色的分割。让我们看看如何帮助他为他的机器人建立一个强大的颜色检测系统。
文章组织如下:
在本节中,我们将介绍计算机视觉中使用的一些重要的颜色空间。我们不会描述它们背后的理论,因为它可以在维基百科上找到。相反,我们将建立一个基本的直觉,并学习一些重要的性质,这将对以后的决策有用。
让我们加载两个相同立方体的图像。默认情况下以BGR格式加载。我们可以使用OpenCV函数cvtColor()
在不同的颜色空间之间进行转换,稍后会展示。
第一幅图像是在阳光明媚的室外条件下拍摄的,第二幅是在室内正常光照条件下拍摄的。
RGB颜色空间具有以下属性:
LAB颜色空间有三个组成部分。
LAB颜色空间与RGB颜色空间有很大的不同。在RGB颜色空间中,颜色信息被分为三个通道,但同样的三个通道也编码亮度信息。另一方面,在Lab颜色空间中,L通道与颜色信息无关,只对亮度进行编码。另外两个通道编码颜色。
它具有以下属性。
YCrCb颜色空间是由RGB颜色空间派生而来的,它有以下三个组成部分。
这个颜色空间具有以下属性。
HSV颜色空间有以下三个组成部分:
让我们列举它的一些属性。
现在我们已经对不同的颜色空间有了一些了解,让我们首先尝试使用它们来检测立方体中的绿色。
交互式GUI代码如下:
(1)Python
interactiveColorDetect.py
import cv2,argparse,glob
import numpy as np
# 鼠标回调函数
def showPixelValue(event,x,y,flags,param):
global img, combinedResult, placeholder
if event == cv2.EVENT_MOUSEMOVE:
# 从鼠标在(x,y)中的位置获取像素值
bgr = img[y,x]
# 将BGR像素转换为其他颜色格式
ycb = cv2.cvtColor(np.uint8([[bgr]]),cv2.COLOR_BGR2YCrCb)[0][0]
lab = cv2.cvtColor(np.uint8([[bgr]]),cv2.COLOR_BGR2Lab)[0][0]
hsv = cv2.cvtColor(np.uint8([[bgr]]),cv2.COLOR_BGR2HSV)[0][0]
# 创建一个空占位符来显示值
placeholder = np.zeros((img.shape[0],400,3),dtype=np.uint8)
# 用颜色空间的值填充占位符
cv2.putText(placeholder, "BGR {}".format(bgr), (20, 70), cv2.FONT_HERSHEY_COMPLEX, .9, (255,255,255), 1, cv2.LINE_AA)
cv2.putText(placeholder, "HSV {}".format(hsv), (20, 140), cv2.FONT_HERSHEY_COMPLEX, .9, (255,255,255), 1, cv2.LINE_AA)
cv2.putText(placeholder, "YCrCb {}".format(ycb), (20, 210), cv2.FONT_HERSHEY_COMPLEX, .9, (255,255,255), 1, cv2.LINE_AA)
cv2.putText(placeholder, "LAB {}".format(lab), (20, 280), cv2.FONT_HERSHEY_COMPLEX, .9, (255,255,255), 1, cv2.LINE_AA)
# 将两个结果合并在一个图像中并排显示
combinedResult = np.hstack([img,placeholder])
cv2.imshow('PRESS P for Previous, N for Next Image',combinedResult)
if __name__ == '__main__' :
# 加载图像并设置鼠标回调函数
global img
files = glob.glob('images/rub*.jpg')
files.sort()
img = cv2.imread(files[0])
img = cv2.resize(img,(400,400))
cv2.imshow('PRESS P for Previous, N for Next Image',img)
# 创建一个空窗口
cv2.namedWindow('PRESS P for Previous, N for Next Image')
# 为鼠标上的任何事件创建一个回调函数
cv2.setMouseCallback('PRESS P for Previous, N for Next Image',showPixelValue)
i = 0
while(1):
k = cv2.waitKey(1) & 0xFF
# 检查文件夹中的下一个图像
if k == ord('n'):
i += 1
img = cv2.imread(files[i%len(files)])
img = cv2.resize(img,(400,400))
cv2.imshow('PRESS P for Previous, N for Next Image',img)
# 检查文件夹中的前一个图像
elif k == ord('p'):
i -= 1
img = cv2.imread(files[i%len(files)])
img = cv2.resize(img,(400,400))
cv2.imshow('PRESS P for Previous, N for Next Image',img)
elif k == 27:
cv2.destroyAllWindows()
break
(2) C++
interactiveColorDetect.cpp
#include "opencv2/opencv.hpp"
#include
using namespace cv;
using namespace std;
//全局变量
Mat img, placeholder;
// 鼠标上的任何事件的回调函数
void onMouse( int event, int x, int y, int flags, void* userdata )
{
if( event == EVENT_MOUSEMOVE )
{
Vec3b bgrPixel(img.at<Vec3b>(y, x));
Mat3b hsv,ycb,lab;
// 从向量创建 Mat 对象,因为 cvtColor 接受一个 Mat 对象
Mat3b bgr (bgrPixel);
//将单个像素的BGR Mat转换为其他格式
cvtColor(bgr, ycb, COLOR_BGR2YCrCb);
cvtColor(bgr, hsv, COLOR_BGR2HSV);
cvtColor(bgr, lab, COLOR_BGR2Lab);
//从 Mat 取回向量
Vec3b hsvPixel(hsv.at<Vec3b>(0,0));
Vec3b ycbPixel(ycb.at<Vec3b>(0,0));
Vec3b labPixel(lab.at<Vec3b>(0,0));
// 创建一个空的占位符来显示值
placeholder = Mat::zeros(img.rows,400,CV_8UC3);
//用颜色空间的值填充占位符
putText(placeholder, format("BGR [%d, %d, %d]",bgrPixel[0],bgrPixel[1],bgrPixel[2]), Point(20, 70), FONT_HERSHEY_COMPLEX, .9, Scalar(255,255,255), 1);
putText(placeholder, format("HSV [%d, %d, %d]",hsvPixel[0],hsvPixel[1],hsvPixel[2]), Point(20, 140), FONT_HERSHEY_COMPLEX, .9, Scalar(255,255,255), 1);
putText(placeholder, format("YCrCb [%d, %d, %d]",ycbPixel[0],ycbPixel[1],ycbPixel[2]), Point(20, 210), FONT_HERSHEY_COMPLEX, .9, Scalar(255,255,255), 1);
putText(placeholder, format("LAB [%d, %d, %d]",labPixel[0],labPixel[1],labPixel[2]), Point(20, 280), FONT_HERSHEY_COMPLEX, .9, Scalar(255,255,255), 1);
Size sz1 = img.size();
Size sz2 = placeholder.size();
//将两个结果合并在一个图像中并排显示
Mat combinedResult(sz1.height, sz1.width+sz2.width, CV_8UC3);
Mat left(combinedResult, Rect(0, 0, sz1.width, sz1.height));
img.copyTo(left);
Mat right(combinedResult, Rect(sz1.width, 0, sz2.width, sz2.height));
placeholder.copyTo(right);
imshow("PRESS P for Previous, N for Next Image", combinedResult);
}
}
int main( int argc, const char** argv )
{
// 读取输入图像
int image_number = 0;
int nImages = 10;
if(argc > 1)
nImages = atoi(argv[1]);
char filename[20];
sprintf(filename,"images/rub%02d.jpg",image_number%nImages);
img = imread(filename);
// 将图像大小调整为 400x400
Size rsize(400,400);
resize(img,img,rsize);
if(img.empty())
{
return -1;
}
// 创建一个空窗口
namedWindow("PRESS P for Previous, N for Next Image", WINDOW_AUTOSIZE);
// 为鼠标上的任何事件创建一个回调函数
setMouseCallback( "PRESS P for Previous, N for Next Image", onMouse );
imshow( "PRESS P for Previous, N for Next Image", img );
while(1)
{
char k = waitKey(1) & 0xFF;
if (k == 27)
break;
//检查文件夹中的下一个图像
if (k =='n')
{
image_number++;
sprintf(filename,"images/rub%02d.jpg",image_number%nImages);
img = imread(filename);
resize(img,img,rsize);
}
//检查文件夹中先前的图像
else if (k =='p')
{
image_number--;
sprintf(filename,"images/rub%02d.jpg",image_number%nImages);
img = imread(filename);
resize(img,img,rsize);
}
}
return 0;
}
步骤2
:应用阈值进行分割inRange()
来查找绿色像素的mask,然后使用bitwise_and()
操作使用mask从图像中获取绿色像素。interactiveColorSegment.py
import cv2,time,argparse,glob
import numpy as np
# 要跟踪的全局变量
show = False
def onTrackbarActivity(x):
global show
show = True
pass
if __name__ == '__main__' :
# 获取文件名
files = glob.glob('images/rub*.jpg')
files.sort()
# 加载图片
original = cv2.imread(files[0])
# 调整图像大小
rsize = 250
original = cv2.resize(original,(rsize,rsize))
# 屏幕上窗口开始的位置
initialX = 50
initialY = 50
# 创建显示图像的窗口
cv2.namedWindow('P-> Previous, N-> Next',cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('SelectBGR',cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('SelectHSV',cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('SelectYCB',cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('SelectLAB',cv2.WINDOW_AUTOSIZE)
# 移动窗口,将它们水平堆叠
cv2.moveWindow('P-> Previous, N-> Next',initialX,initialY)
cv2.moveWindow('SelectBGR',initialX + (rsize + 5),initialY)
cv2.moveWindow('SelectHSV',initialX + 2*(rsize + 5),initialY)
cv2.moveWindow('SelectYCB',initialX + 3*(rsize + 5),initialY)
cv2.moveWindow('SelectLAB',initialX + 4*(rsize + 5),initialY)
#创建跟踪条以获取YCrCb的值
cv2.createTrackbar('CrMin','SelectYCB',0,255,onTrackbarActivity)
cv2.createTrackbar('CrMax','SelectYCB',0,255,onTrackbarActivity)
cv2.createTrackbar('CbMin','SelectYCB',0,255,onTrackbarActivity)
cv2.createTrackbar('CbMax','SelectYCB',0,255,onTrackbarActivity)
cv2.createTrackbar('YMin','SelectYCB',0,255,onTrackbarActivity)
cv2.createTrackbar('YMax','SelectYCB',0,255,onTrackbarActivity)
#创建跟踪条来获取HSV的值
cv2.createTrackbar('HMin','SelectHSV',0,180,onTrackbarActivity)
cv2.createTrackbar('HMax','SelectHSV',0,180,onTrackbarActivity)
cv2.createTrackbar('SMin','SelectHSV',0,255,onTrackbarActivity)
cv2.createTrackbar('SMax','SelectHSV',0,255,onTrackbarActivity)
cv2.createTrackbar('VMin','SelectHSV',0,255,onTrackbarActivity)
cv2.createTrackbar('VMax','SelectHSV',0,255,onTrackbarActivity)
#创建跟踪条来获取BGR的值
cv2.createTrackbar('BGRBMin','SelectBGR',0,255,onTrackbarActivity)
cv2.createTrackbar('BGRBMax','SelectBGR',0,255,onTrackbarActivity)
cv2.createTrackbar('BGRGMin','SelectBGR',0,255,onTrackbarActivity)
cv2.createTrackbar('BGRGMax','SelectBGR',0,255,onTrackbarActivity)
cv2.createTrackbar('BGRRMin','SelectBGR',0,255,onTrackbarActivity)
cv2.createTrackbar('BGRRMax','SelectBGR',0,255,onTrackbarActivity)
#创建跟踪条来获取LAB的值
cv2.createTrackbar('LABLMin','SelectLAB',0,255,onTrackbarActivity)
cv2.createTrackbar('LABLMax','SelectLAB',0,255,onTrackbarActivity)
cv2.createTrackbar('LABAMin','SelectLAB',0,255,onTrackbarActivity)
cv2.createTrackbar('LABAMax','SelectLAB',0,255,onTrackbarActivity)
cv2.createTrackbar('LABBMin','SelectLAB',0,255,onTrackbarActivity)
cv2.createTrackbar('LABBMax','SelectLAB',0,255,onTrackbarActivity)
# 初始显示所有图像
cv2.imshow('SelectHSV',original)
cv2.imshow('SelectYCB',original)
cv2.imshow('SelectLAB',original)
cv2.imshow('SelectBGR',original)
i = 0
while(1):
cv2.imshow('P-> Previous, N-> Next',original)
k = cv2.waitKey(1) & 0xFF
# 检查文件夹中的下一个图像
if k == ord('n'):
i += 1
original = cv2.imread(files[i%len(files)])
original = cv2.resize(original,(rsize,rsize))
show = True
# 检查文件夹中的先前图像
elif k == ord('p'):
i -= 1
original = cv2.imread(files[i%len(files)])
original = cv2.resize(original,(rsize,rsize))
show = True
# 按下esc键后关闭所有窗口
elif k == 27:
break
if show: # 如果在轨迹栏上有任何事件
show = False
# 从BGR跟踪器获取值
BMin = cv2.getTrackbarPos('BGRBMin','SelectBGR')
GMin = cv2.getTrackbarPos('BGRGMin','SelectBGR')
RMin = cv2.getTrackbarPos('BGRRMin','SelectBGR')
BMax = cv2.getTrackbarPos('BGRBMax','SelectBGR')
GMax = cv2.getTrackbarPos('BGRGMax','SelectBGR')
RMax = cv2.getTrackbarPos('BGRRMax','SelectBGR')
minBGR = np.array([BMin, GMin, RMin])
maxBGR = np.array([BMax, GMax, RMax])
# 从HSV跟踪器获取值
HMin = cv2.getTrackbarPos('HMin','SelectHSV')
SMin = cv2.getTrackbarPos('SMin','SelectHSV')
VMin = cv2.getTrackbarPos('VMin','SelectHSV')
HMax = cv2.getTrackbarPos('HMax','SelectHSV')
SMax = cv2.getTrackbarPos('SMax','SelectHSV')
VMax = cv2.getTrackbarPos('VMax','SelectHSV')
minHSV = np.array([HMin, SMin, VMin])
maxHSV = np.array([HMax, SMax, VMax])
# 从LAB跟踪器获取值
LMin = cv2.getTrackbarPos('LABLMin','SelectLAB')
AMin = cv2.getTrackbarPos('LABAMin','SelectLAB')
BMin = cv2.getTrackbarPos('LABBMin','SelectLAB')
LMax = cv2.getTrackbarPos('LABLMax','SelectLAB')
AMax = cv2.getTrackbarPos('LABAMax','SelectLAB')
BMax = cv2.getTrackbarPos('LABBMax','SelectLAB')
minLAB = np.array([LMin, AMin, BMin])
maxLAB = np.array([LMax, AMax, BMax])
# 从YCrCb跟踪器获取值
YMin = cv2.getTrackbarPos('YMin','SelectYCB')
CrMin = cv2.getTrackbarPos('CrMin','SelectYCB')
CbMin = cv2.getTrackbarPos('CbMin','SelectYCB')
YMax = cv2.getTrackbarPos('YMax','SelectYCB')
CrMax = cv2.getTrackbarPos('CrMax','SelectYCB')
CbMax = cv2.getTrackbarPos('CbMax','SelectYCB')
minYCB = np.array([YMin, CrMin, CbMin])
maxYCB = np.array([YMax, CrMax, CbMax])
# 将BGR图像转换为其他颜色空间
imageBGR = np.copy(original)
imageHSV = cv2.cvtColor(original,cv2.COLOR_BGR2HSV)
imageYCB = cv2.cvtColor(original,cv2.COLOR_BGR2YCrCb)
imageLAB = cv2.cvtColor(original,cv2.COLOR_BGR2LAB)
# 使用从轨迹栏获得的最小值和最大值创建掩码,并应用bitewise_and操作来获得结果
maskBGR = cv2.inRange(imageBGR,minBGR,maxBGR)
resultBGR = cv2.bitwise_and(original, original, mask = maskBGR)
maskHSV = cv2.inRange(imageHSV,minHSV,maxHSV)
resultHSV = cv2.bitwise_and(original, original, mask = maskHSV)
maskYCB = cv2.inRange(imageYCB,minYCB,maxYCB)
resultYCB = cv2.bitwise_and(original, original, mask = maskYCB)
maskLAB = cv2.inRange(imageLAB,minLAB,maxLAB)
resultLAB = cv2.bitwise_and(original, original, mask = maskLAB)
# 显示结果
cv2.imshow('SelectBGR',resultBGR)
cv2.imshow('SelectYCB',resultYCB)
cv2.imshow('SelectLAB',resultLAB)
cv2.imshow('SelectHSV',resultHSV)
cv2.destroyAllWindows()
(2) C++
interactiveColorSegment.cpp
#include "opencv2/opencv.hpp"
#include
#include
using namespace cv;
using namespace std;
// 要跟踪的全局变量
bool show = false;
// 为跟踪栏上的事件创建回调
void onTrackbarActivity(int pos, void* userdata){
// 只需要在全局变量中指定有一个事件
show = true;
return;
}
int main(int argc, char **argv)
{
int image_number = 0;
int nImages = 10;
if(argc > 1)
nImages = atoi(argv[1]);
char filename[20];
sprintf(filename,"images/rub%02d.jpg",image_number%nImages);
Mat original = imread(filename);
// 图像调整宽度和高度
int resizeHeight = 250;
int resizeWidth = 250;
Size rsize(resizeHeight,resizeWidth);
resize(original, original, rsize);
// 屏幕上窗口开始的位置
int initialX = 50;
int initialY = 50;
// 创建显示图像的窗口
namedWindow("P-> Previous, N-> Next", WINDOW_AUTOSIZE);
namedWindow("SelectBGR", WINDOW_AUTOSIZE);
namedWindow("SelectHSV", WINDOW_AUTOSIZE);
namedWindow("SelectYCB", WINDOW_AUTOSIZE);
namedWindow("SelectLAB", WINDOW_AUTOSIZE);
// 移动窗口,将它们水平堆叠
moveWindow("P-> Previous, N-> Next", initialX, initialY);
moveWindow("SelectBGR", initialX + 1 * (resizeWidth + 5), initialY);
moveWindow("SelectHSV", initialX + 2 * (resizeWidth + 5), initialY);
moveWindow("SelectYCB", initialX + 3 * (resizeWidth + 5), initialY);
moveWindow("SelectLAB", initialX + 4 * (resizeWidth + 5), initialY);
// 创建跟踪条以获取YCrCb的值
createTrackbar("CrMin", "SelectYCB", 0, 255, onTrackbarActivity);
createTrackbar("CrMax", "SelectYCB", 0, 255, onTrackbarActivity);
createTrackbar("CbMin", "SelectYCB", 0, 255, onTrackbarActivity);
createTrackbar("CbMax", "SelectYCB", 0, 255, onTrackbarActivity);
createTrackbar("YMin", "SelectYCB", 0, 255, onTrackbarActivity);
createTrackbar("YMax", "SelectYCB", 0, 255, onTrackbarActivity);
// 创建跟踪条来获取HSV的值
createTrackbar("HMin", "SelectHSV", 0, 180, onTrackbarActivity);
createTrackbar("HMax", "SelectHSV", 0, 180, onTrackbarActivity);
createTrackbar("SMin", "SelectHSV", 0, 255, onTrackbarActivity);
createTrackbar("SMax", "SelectHSV", 0, 255, onTrackbarActivity);
createTrackbar("VMin", "SelectHSV", 0, 255, onTrackbarActivity);
createTrackbar("VMax", "SelectHSV", 0, 255, onTrackbarActivity);
// 创建跟踪条来获取BGR的值
createTrackbar("BMin", "SelectBGR", 0, 255, onTrackbarActivity);
createTrackbar("BMax", "SelectBGR", 0, 255, onTrackbarActivity);
createTrackbar("GMin", "SelectBGR", 0, 255, onTrackbarActivity);
createTrackbar("GMax", "SelectBGR", 0, 255, onTrackbarActivity);
createTrackbar("RMin", "SelectBGR", 0, 255, onTrackbarActivity);
createTrackbar("RMax", "SelectBGR", 0, 255, onTrackbarActivity);
// 创建跟踪条来获取LAB的值
createTrackbar("LMin", "SelectLAB", 0, 255, onTrackbarActivity);
createTrackbar("LMax", "SelectLAB", 0, 255, onTrackbarActivity);
createTrackbar("AMin", "SelectLAB", 0, 255, onTrackbarActivity);
createTrackbar("AMax", "SelectLAB", 0, 255, onTrackbarActivity);
createTrackbar("BMin", "SelectLAB", 0, 255, onTrackbarActivity);
createTrackbar("BMax", "SelectLAB", 0, 255, onTrackbarActivity);
// 初始显示所有图像
imshow("SelectHSV", original);
imshow("SelectYCB", original);
imshow("SelectLAB", original);
imshow("SelectBGR", original);
//声明局部变量
int BMin, GMin, RMin;
int BMax, GMax, RMax;
Scalar minBGR, maxBGR;
int HMin, SMin, VMin;
int HMax, SMax, VMax;
Scalar minHSV, maxHSV;
int LMin, aMin, bMin;
int LMax, aMax, bMax;
Scalar minLab, maxLab;
int YMin, CrMin, CbMin;
int YMax, CrMax, CbMax;
Scalar minYCrCb, maxYCrCb;
Mat imageBGR, imageHSV, imageLab, imageYCrCb;
Mat maskBGR, maskHSV, maskLab, maskYCrCb;
Mat resultBGR, resultHSV, resultLab, resultYCrCb;
char k;
while (1){
imshow("P-> Previous, N-> Next", original);
k = waitKey(1) & 0xFF;
//检查文件夹中的下一个图像
if (k =='n')
{
image_number++;
sprintf(filename,"images/rub%02d.jpg",image_number%nImages);
original = imread(filename);
resize(original,original,rsize);
show = true;
}
//检查文件夹中先前的图像
else if (k =='p')
{
image_number--;
sprintf(filename,"images/rub%02d.jpg",image_number%nImages);
original = imread(filename);
resize(original,original,rsize);
show = true;
}
// 按下esc键后关闭所有窗口
if (k == 27){
break;
}
if (show) {
//如果在轨迹栏上有任何事件
show = false;
// 从BGR trackbar获取值
BMin = getTrackbarPos("BMin", "SelectBGR");
GMin = getTrackbarPos("GMin", "SelectBGR");
RMin = getTrackbarPos("RMin", "SelectBGR");
BMax = getTrackbarPos("BMax", "SelectBGR");
GMax = getTrackbarPos("GMax", "SelectBGR");
RMax = getTrackbarPos("RMax", "SelectBGR");
minBGR = Scalar(BMin, GMin, RMin);
maxBGR = Scalar(BMax, GMax, RMax);
// 从HSV轨迹栏获取值
HMin = getTrackbarPos("HMin", "SelectHSV");
SMin = getTrackbarPos("SMin", "SelectHSV");
VMin = getTrackbarPos("VMin", "SelectHSV");
HMax = getTrackbarPos("HMax", "SelectHSV");
SMax = getTrackbarPos("SMax", "SelectHSV");
VMax = getTrackbarPos("VMax", "SelectHSV");
minHSV = Scalar(HMin, SMin, VMin);
maxHSV = Scalar(HMax, SMax, VMax);
// 从LAB跟踪栏获取值
LMin = getTrackbarPos("LMin", "SelectLAB");
aMin = getTrackbarPos("AMin", "SelectLAB");
bMin = getTrackbarPos("BMin", "SelectLAB");
LMax = getTrackbarPos("LMax", "SelectLAB");
aMax = getTrackbarPos("AMax", "SelectLAB");
bMax = getTrackbarPos("BMax", "SelectLAB");
minLab = Scalar(LMin, aMin, bMin);
maxLab = Scalar(LMax, aMax, bMax);
// 从YCrCb轨迹栏获取值
YMin = getTrackbarPos("YMin", "SelectYCB");
CrMin = getTrackbarPos("CrMin", "SelectYCB");
CbMin = getTrackbarPos("CbMin", "SelectYCB");
YMax = getTrackbarPos("YMax", "SelectYCB");
CrMax = getTrackbarPos("CrMax", "SelectYCB");
CbMax = getTrackbarPos("CbMax", "SelectYCB");
minYCrCb = Scalar(YMin, CrMin, CbMin);
maxYCrCb = Scalar(YMax, CrMax, CbMax);
// 将BGR图像转换为其他颜色空间
original.copyTo(imageBGR);
cvtColor(original, imageHSV, COLOR_BGR2HSV);
cvtColor(original, imageYCrCb, COLOR_BGR2YCrCb);
cvtColor(original, imageLab, COLOR_BGR2Lab);
// 使用从轨迹栏获得的最小值和最大值创建掩码,并应用bitewise_and操作来获得结果
inRange(imageBGR, minBGR, maxBGR, maskBGR);
resultBGR = Mat::zeros(original.rows, original.cols, CV_8UC3);
bitwise_and(original, original, resultBGR, maskBGR);
inRange(imageHSV, minHSV, maxHSV, maskHSV);
resultHSV = Mat::zeros(original.rows, original.cols, CV_8UC3);
bitwise_and(original, original, resultHSV, maskHSV);
inRange(imageYCrCb, minYCrCb, maxYCrCb, maskYCrCb);
resultYCrCb = Mat::zeros(original.rows, original.cols, CV_8UC3);
bitwise_and(original, original, resultYCrCb, maskYCrCb);
inRange(imageLab, minLab, maxLab, maskLab);
resultLab = Mat::zeros(original.rows, original.cols, CV_8UC3);
bitwise_and(original, original, resultLab, maskLab);
// 结果显示
imshow("SelectBGR", resultBGR);
imshow("SelectYCB", resultYCrCb);
imshow("SelectLAB", resultLab);
imshow("SelectHSV", resultHSV);
}
}
destroyAllWindows();
return 0;
}
第一步
:数据收集步骤2
:计算密度图# 导入所需的包
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import cv2, glob
import numpy as np
# 指定要绘制的直方图的颜色
color = 'pieces/yellow'
#图是否应该是完整的还是缩小的
zoom = 1
# 加载文件夹中的所有文件
files = glob.glob(color + '*.jpg')
files.sort()
# 空数组用于分离的通道
B = np.array([])
G = np.array([])
R = np.array([])
H = np.array([])
S = np.array([])
V = np.array([])
Y = np.array([])
Cr = np.array([])
Cb = np.array([])
LL = np.array([])
LA = np.array([])
LB = np.array([])
# 数据创建
# 将每个文件中的值附加到各自的通道中
for fi in files[:]:
# BGR
im = cv2.imread(fi)
b = im[:, :, 0]
b = b.reshape(b.shape[0] * b.shape[1])
g = im[:, :, 1]
g = g.reshape(g.shape[0] * g.shape[1])
r = im[:, :, 2]
r = r.reshape(r.shape[0] * r.shape[1])
B = np.append(B, b)
G = np.append(G, g)
R = np.append(R, r)
# HSV
hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
h = hsv[:, :, 0]
h = h.reshape(h.shape[0] * h.shape[1])
s = hsv[:, :, 1]
s = s.reshape(s.shape[0] * s.shape[1])
v = hsv[:, :, 2]
v = v.reshape(v.shape[0] * v.shape[1])
H = np.append(H, h)
S = np.append(S, s)
V = np.append(V, v)
# YCrCb
ycb = cv2.cvtColor(im, cv2.COLOR_BGR2YCrCb)
y = ycb[:, :, 0]
y = y.reshape(y.shape[0] * y.shape[1])
cr = ycb[:, :, 1]
cr = cr.reshape(cr.shape[0] * cr.shape[1])
cb = ycb[:, :, 2]
cb = cb.reshape(cb.shape[0] * cb.shape[1])
Y = np.append(Y, y)
Cr = np.append(Cr, cr)
Cb = np.append(Cb, cb)
# Lab
lab = cv2.cvtColor(im, cv2.COLOR_BGR2LAB)
ll = lab[:, :, 0]
ll = ll.reshape(ll.shape[0] * ll.shape[1])
la = lab[:, :, 1]
la = la.reshape(la.shape[0] * la.shape[1])
lb = lab[:, :, 2]
lb = lb.reshape(lb.shape[0] * lb.shape[1])
LL = np.append(LL, ll)
LA = np.append(LA, la)
LB = np.append(LB, lb)
# 绘制柱状图
nbins = 10
plt.figure(figsize=[20, 10])
plt.subplot(2, 3, 1)
plt.hist2d(B, G, bins=nbins, norm=LogNorm())
plt.xlabel('B')
plt.ylabel('G')
plt.title('RGB')
if not zoom:
plt.xlim([0, 255])
plt.ylim([0, 255])
plt.colorbar()
plt.subplot(2, 3, 2)
plt.hist2d(B, R, bins=nbins, norm=LogNorm())
plt.colorbar()
plt.xlabel('B')
plt.ylabel('R')
plt.title('RGB')
if not zoom:
plt.xlim([0, 255])
plt.ylim([0, 255])
plt.subplot(2, 3, 3)
plt.hist2d(R, G, bins=nbins, norm=LogNorm())
plt.colorbar()
plt.xlabel('R')
plt.ylabel('G')
plt.title('RGB')
if not zoom:
plt.xlim([0, 255])
plt.ylim([0, 255])
plt.subplot(2, 3, 4)
plt.hist2d(H, S, bins=nbins, norm=LogNorm())
plt.colorbar()
plt.xlabel('H')
plt.ylabel('S')
plt.title('HSV')
if not zoom:
plt.xlim([0, 180])
plt.ylim([0, 255])
plt.subplot(2, 3, 5)
plt.hist2d(Cr, Cb, bins=nbins, norm=LogNorm())
plt.colorbar()
plt.xlabel('Cr')
plt.ylabel('Cb')
plt.title('YCrCb')
if not zoom:
plt.xlim([0, 255])
plt.ylim([0, 255])
plt.subplot(2, 3, 6)
plt.hist2d(LA, LB, bins=nbins, norm=LogNorm())
plt.colorbar()
plt.xlabel('A')
plt.ylabel('B')
plt.title('LAB')
if not zoom:
plt.xlim([0, 255])
plt.ylim([0, 255])
plt.savefig(color + '.png', bbox_inches='tight')
else:
plt.savefig(color + '-zoom.png', bbox_inches='tight')
plt.show()
当分析blue
图片时候:
当分析green
图片时候:
当分析orange
图片时候:
当分析red
图片时候:
当分析yellow
图片时候:
当光照变化很大时,我们可以看到:
在最后一节中,我将展示检测蓝色和黄色块的结果,方法是从密度图中提取阈值,并将其应用到各自的颜色空间中,方法与第二节相同。当我们在HSV, YCrCb和LAB颜色空间中工作时,我们不必担心强度分量。我们只需要为颜色分量指定阈值。图中显示了我用来生成结果的值。
在上面的结果中,我直接从密度图中取了值。我们也可以选择取密度图中最密集区域的值,这样可以更严格的控制颜色范围。这将留下一些洞和散乱的像素,可以用侵蚀和膨胀,然后过滤。
https://learnopencv.com/color-spaces-in-opencv-cpp-python/