opencv版本号: opencv3.4.1
目录
图像处理中需要对图像的像素点进行遍历,遍历图像像素的算法影响运行速度;以图像反色为例,有以下几种算法;
1. 下标M.at<float>(i, j)
cv::Mat inverseColor1(cv::Mat srcImage)
{
cv::Mat tempImage = srcImage.clone();
int row = tempImage.rows;
int col = tempImage.cols;
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
//对各个通道进行反色处理
tempImage.at<cv::Vec3b>(i,j)[0] = 255 - srcImage.at<cv::Vec3b>(i,j)[0];
tempImage.at<cv::Vec3b>(i,j)[1] = 255 - srcImage.at<cv::Vec3b>(i,j)[1];
tempImage.at<cv::Vec3b>(i,j)[2] = 255 - srcImage.at<cv::Vec3b>(i,j)[2];
}
}
return tempImage;
}
2. 指针遍历Mat::ptr<type>
cv::Mat inverseColor2(cv::Mat srcImage)
{
cv::Mat tempImage = srcImage.clone();
int row = tempImage.rows;
//将3通道转换为单通道
//std::cout << " row=" << row << " cols=" << tempImage.cols << " channels=" << tempImage.channels() << endl;
int nStep = tempImage.cols * tempImage.channels();
for(int i = 0; i < row; i++){
//取源图像指针
const uchar *pSrcData = srcImage.ptr<uchar>(i);
uchar *pResultData = tempImage.ptr<uchar>(i);
for(int j = 0; j < nStep; j++){
pResultData[j] = cv::saturate_cast<uchar>(255-pSrcData[j]);
}
}
return tempImage;
}
3. 迭代器Matlterator_
cv::Mat inverseColor3(cv :: Mat srcImage)
{
cv::Mat tempImage = srcImage.clone();
//初始化源图像迭代器
cv::MatConstIterator_<cv::Vec3b> srcIterStart = srcImage.begin<cv::Vec3b>();
cv::MatConstIterator_<cv::Vec3b> srcIterEnd = srcImage.end<cv::Vec3b>();
//初始化输出图像迭代器
cv::MatIterator_<cv::Vec3b> resIterStart = tempImage.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> resIterEnd = tempImage.end<cv::Vec3b>();
while(srcIterStart != srcIterEnd)
{
(*resIterStart)[0] = 255 - (*srcIterStart)[0];
(*resIterStart)[1] = 255 - (*srcIterStart)[1];
(*resIterStart)[2] = 255 - (*srcIterStart)[2];
srcIterStart++;
resIterStart++;
}
return tempImage;
}
4. isContinuout方法
图像数据的存储行与行间可能是空白单元,即图像行与行间的存储可能是不连续的,所以在使用上述方法进行图像的遍历时,很大程度上会造成指针的移动浪费;所以用isContunuout函数判断图像元素存储是连续的;
cv::Mat inverseColor4(cv :: Mat srcImage)
{
int row = srcImage.rows;
int col = srcImage.cols;
cv::Mat tempImage = srcImage.clone();
//判断是否有连续图像,即是否有像素填充
if(srcImage.isContinuous() && tempImage.isContinuous()){
row = 1;
col = col * srcImage.rows * srcImage.channels();
}
for(int i = 0 ;i < row; i++){
const uchar *pSrcData = srcImage.ptr<uchar>(i);
uchar *pResultData = tempImage.ptr<uchar>(i);
for(int j =0 ; j < col; j++){
*pResultData = 255 - *pSrcData;
pResultData++;
pSrcData++;
}
}
return tempImage;
}
5. LUT查表法
为了减少图像映射的时间复杂度,提供了查找表LUT;
cv::Mat inverseColor5(cv :: Mat srcImage)
{
int row = srcImage.rows;
int col = srcImage.cols;
cv::Mat tempImage = srcImage.clone();
//建立LUT反色table
uchar LutTab[256];
for(int i =0 ; i < 256; i++){
LutTab[i] = 255 - i;
}
cv::Mat lookUpTable(1, 256, CV_8U);
uchar *pData = lookUpTable.data;
//建立映射表
for(int i = 0; i < 256; i++){
pData[i] = LutTab[i];
}
//利用索引查找
cv::LUT(srcImage, lookUpTable, tempImage);
return tempImage;
}
测试代码:
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(srcImage.empty()){
std::cout << "imread failed" << endl;
return -1;
}
double tTime;
tTime = (double)getTickCount();
//cv::Mat dstImage = inverseColor1(srcImage); //运行时间Max 7.30422
//cv::Mat dstImage = inverseColor2(srcImage); //运行时间Max 1.88004
//cv::Mat dstImage = inverseColor3(srcImage); //运行时间Max 8.38001
//cv::Mat dstImage = inverseColor4(srcImage); //运行时间Max 1.66753
cv::Mat dstImage = inverseColor5(srcImage); //运行时间Max 1.26254
tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
std::cout << tTime << std::endl;
cv::imwrite("./lena_inverse5.jpg", dstImage);
return 0;
}
getTickCount()和getTickFrequency()函数用来计时测试代码的运行时间;