我正在尝试识别图片中的四个HSV间隔,结果图像应该由0,1,2,3组成,其中这些代表已识别的颜色索引。
我想尽可能多地使用opencv API,以减少执行时间和循环开销。我尝试过使用inRange和addWeighted,但我没有提出功能算法。你能帮帮我吗?
例如,假设我想要分类110<H<130 && S > 100 && V > 100 as color0
140<H<160 && S > 100 && V > 100 as color1
50<H<70 && S > 100 && V > 100 as color2
问题是我必须以不同的间隔同时处理所有三个通道,所以我认为LUT方式(1通道或3个不同的通道)不是从1获得1D分类输出矩阵的正确方法3D输入矩阵。
答案 0 :(得分:2)
我还没有尝试过,但我认为查找表(LUT)是理想的。假设您的范围是0-30,31-78,79-91和92-100,您将制作256个元素的LUT,其中前31个条目为零,接下来的48个条目为1,依此类推。然后拨打cv::LUT()
。
LUT的优点是输出值只是从Hue值索引的表中获取,这意味着每个像素没有多个if
语句,这意味着CPU在确定分支时不会停顿目的地 - 所以它应该非常快。
我做了一些实验,无法让内置的LUT()
函数快速执行此设置 - 还必须使用split()
来减慢速度。我用这个HSL色轮作为测试图像。
这是代码。首先,它使用if
语句来处理条件并对其进行计时,然后重复处理但使用3个LUT来确定输出值:
// https://stackoverflow.com/q/49333257/2836621
#include <iostream>
#include <cstdio>
#include <chrono>
#include <thread>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int
main(int argc,char*argv[])
{
// Open input and check success
Mat img = cv::imread("start.png",-CV_LOAD_IMAGE_ANYDEPTH);
if (img.empty()){
cerr << "ERROR: Failed to open start.png" << endl;
exit(1);
}
// Create HSV version
Mat hsvMat;
cv::cvtColor(img,hsvMat,CV_BGR2HSV);
// Create result Mat, same dimensions as input, and pointer to its data
Mat result;
cv::cvtColor(img,result,CV_BGR2GRAY);
unsigned char* r;
// Various constants
const int Sthreshold = 100;
const int Vthreshold = 100;
const int Hthreshold[]={110,130,140,160,50,70};
// Process with if statements and time it
double t = (double)getTickCount();
// Iterate over rows and columns of hsvMat
Vec3b *thisRow;
for(int j=0;j<hsvMat.rows;++j)
{
// Get pointers to input and output rows
thisRow = hsvMat.ptr<Vec3b>(j);
r = result.ptr<unsigned char>(j);
// Iterate over cols
for(int i=0;i<hsvMat.cols;++i)
{
auto H=thisRow[i][0]; // Pick up this pixel's Hue
auto S=thisRow[i][1]; // Pick up this pixel's Sat
auto V=thisRow[i][2]; // Pick up this pixel's Value
// Pre-set output colour to black
unsigned char v=0;
if((V>Vthreshold) && (S>Sthreshold)){
// Set result based on Hue
if((H>Hthreshold[0]) && (H<Hthreshold[1])){
v=64;
} else if((H>Hthreshold[2]) && (H<Hthreshold[3])){
v=128;
} else if((H>Hthreshold[4]) && (H<Hthreshold[5])){
v=192;
}
}
r[i]=v;
}
}
t = (((double)getTickCount() - t)*1000000)/getTickFrequency();
cout << "Time with if statements: " << t << "us" << std::endl;
// Write to disk for checking
imwrite("resultptr.png",result);
// Now do setup for LUT method
// Pre-create LUTs for Hue, Saturation, Value
unsigned char HLUT[256]={0};
unsigned char SLUT[256]={0};
unsigned char VLUT[256]={0};
for(int i=0;i<256;i++){
if(i>Sthreshold){SLUT[i]=1;}
if(i>Vthreshold){VLUT[i]=1;}
if((i>Hthreshold[0]) && (i<Hthreshold[1])){
HLUT[i]=64;
} else if((i>Hthreshold[2]) && (i<Hthreshold[3])){
HLUT[i]=128;
} else if((i>Hthreshold[4]) && (i<Hthreshold[5])){
HLUT[i]=192;
}
}
// Process with LUT and time it
t = (double)getTickCount();
// Iterate over rows and columns of hsvMat
for(int j=0;j<hsvMat.rows;++j)
{
// Get pointers to input and output rows
thisRow = hsvMat.ptr<Vec3b>(j);
r = result.ptr<unsigned char>(j);
// Iterate over cols
for(int i=0;i<hsvMat.cols;++i)
{
auto H=thisRow[i][0]; // Pick up this pixel's Hue
auto S=thisRow[i][1]; // Pick up this pixel's Sat
auto V=thisRow[i][2]; // Pick up this pixel's Value
r[i]=HLUT[H] * SLUT[S] * VLUT[V]; // Lookup output pixel
}
}
t = (((double)getTickCount() - t)*1000000)/getTickFrequency();
cout << "Time with LUT: " << t << "us" << std::endl;
// Write to disk for checking
imwrite("resultLUT.png",result);
}
结果是:
我的iMac(clang++ -march=native -O3
)上的时间是:
Time with if statements: 38.429us
Time with LUT: 24.31us
如果有人想要获取代码并尝试第二组循环的替代方法,请随意尝试发布您获得的内容,但保持第一组循环不变以供参考。