image.row().setTo()
快捷地设置某些行、列的值可以获取某行、列的图像再调用setTo()
函数进行设置。
对于图像image:
image.row()
返回cv::Mat
,其通道数和image相同,宽高是(image.cols,1)
image.col()
返回cv::Mat
,其通道数和image相同,宽高是(1,image.rows)
image.setTo(cv::Scalar(255,255,0))
将image
设为指定的值cv::Scalar(255,255,0)
。
#include
#include
#include
int main()
{
cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
for (int i = 0; i != 10; ++i)
{
img.row(i).setTo(cv::Scalar(0, 255, 255));
img.col(i).setTo(cv::Scalar(0, 255, 255));
}
for (int i = img.rows-10; i != img.rows; ++i)
{
img.row(i).setTo(cv::Scalar(0, 255, 255));
}
for (int i = img.cols - 10; i != img.cols; ++i)
{
img.col(i).setTo(cv::Scalar(0, 255, 255));
}
cv::imshow("img", img);
cv::waitKey(0);
}
效果如图1所示:
图像说白了就是普通的矩阵,可以进行加减乘除与或非等运算,再OpenCV中有相应的函数来完成这些操作,同时也重载了相应的运算符。
例如图像的加权相加:
#include
#include
#include
int main()
{
cv::Mat img1 = cv::imread("greed.jpg", 1);
cv::Mat img2 = cv::imread("red.jpg", 1);
cv::Mat img;
/* 使用函数进行加权相加 */
cv::addWeighted(img1, 1.0, img2, 1.0, 0., img, -1);
/* 或者使用重载运算符进行加权相加 */
// img = 1.0 * img1 + 1.0 * img2;
cv::imshow("img", img);
cv::waitKey(0);
}
其中greed.jpg:
cv::split()、cv::merge()
cv::split()
实现通道分离、cv::merge()
实现通道融合。
#include
#include
#include
#include
int main()
{
cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
cv::imshow("img", img);
std::vector<cv::Mat> planes;
cv::split(img, planes);
//cv::imshow("red-channel.jpg", planes[2]);
//cv::imshow("green-channel.jpg", planes[1]);
//cv::imshow("blue-channel.jpg", planes[0]);
cv::Mat result;
/* img与result的每个像素都是完全相同的 */
cv::merge(planes, result);
cv::imshow("result", result);
/* 求img与result的差 */
cv::Mat diff = img - result;
for (int i = 0; i != img.rows;++i)
{
cv::Vec3b *ptr = diff.ptr<cv::Vec3b>(i);
for (int j = 0; j != img.cols; ++j)
{
/* 由于diff三个通道每个像素的灰度值都是0,因此不会进入if语句块 */
if (ptr[j]!=cv::Vec3b(0,0,0))
{
std::cout << ptr[j] << std::endl;
}
}
}
cv::waitKey(0);
}
构建简单的算法去除图像中某种特定颜色的像素。
代码如下:
RemoveColor.h
:
#pragma once
#include
class RemoveColor
{
public:
RemoveColor(cv::Vec3b target,int dist);
~RemoveColor();
void setTarget(cv::Vec3b target);
cv::Vec3b getTarget();
void setMaxDist(int max_dist);
int getMaxDist();
int calcuDist(cv::Vec3b color);
cv::Mat process(cv::Mat img);
private:
cv::Vec3b m_target;
int m_max_dist;
};
RemoveColor.cpp
:
#include "RemoveColor.h"
RemoveColor::RemoveColor(cv::Vec3b target, int dist)
{
this->m_max_dist = dist;
this->m_target = target;
}
void RemoveColor::setTarget(cv::Vec3b target)
{
this->m_target = target;
}
cv::Vec3b RemoveColor::getTarget()
{
return this->m_target;
}
void RemoveColor::setMaxDist(int max_dist)
{
this->m_max_dist = max_dist;
}
int RemoveColor::getMaxDist()
{
return this->m_max_dist;
}
int RemoveColor::calcuDist(cv::Vec3b color)
{
return (abs(this->m_target[0] - color[0]) +
abs(this->m_target[1] - color[1]) +
abs(this->m_target[2] - color[2]));
}
cv::Mat RemoveColor::process(cv::Mat img)
{
cv::Mat result;
result.create(img.size(), CV_8UC1);
cv::Mat_<cv::Vec3b>::const_iterator itbeg = img.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend = img.end<cv::Vec3b>();
cv::Mat_<uchar>::iterator it_result = result.begin<uchar>();
/* 迭代器遍历img和result */
for (auto it = itbeg; it != itend; ++it, ++it_result)
{
if (calcuDist(*it) <= m_max_dist)
{
*it_result = 0;
}
else
{
*it_result = ((*it)[0] + (*it)[1] + (*it)[2])/3;
}
}
return result;
}
RemoveColor::~RemoveColor(){}
调用方法:
#include
#include
#include "RemoveColor.h"
int main()
{
cv::Mat_<cv::Vec3b> img = cv::imread("ALBT9701_.jpg");
/* 构造 */
RemoveColor rc(cv::Vec3b(255,255,0),0);
/* 处理 */
cv::Mat result = rc.process(img);
cv::imshow("result", result);
cv::imshow("img", img);
cv::waitKey(0);
}
上面int calcuDist(cv::Vec3b color);
也可以用cv::absdiff()
,cv::sum()
来实现。举例说明这两个函数的使用方法:
cv::Vec3b result;
cv::Vec3b color(1, 2, 3);
cv::Vec3b target(11, 22, 33);
cv::absdiff(color, target, result); // result的结果是(10,20,30)
/* cv::sum()返回值是四维的,这里只需第一维 */
auto it = cv::sum(result)[0]; // it == 60
cv::floodFill()
cv::floodFill()
可以查找指定像素颜色并将其设置为目标颜色,该函数会将指定的某个像素位置周围的连续区域都进行判断。例如:
#include
#include
int main()
{
cv::Mat_<cv::Vec3b> img = cv::imread("ALBT9701__.jpg");
cv::floodFill(img, cv::Point(550, 250), cv::Scalar(255, 0, 0),
(cv::Rect*)0, cv::Scalar(35, 35, 35), cv::Scalar(35, 35, 35),
cv::FLOODFILL_FIXED_RANGE);
cv::imshow("img", img);
cv::waitKey(0);
}
图5是输入图像,图6是处理后的效果。坐标(500,250)
处于颜色(255,255,0)
大矩形位置,可以看到整个大矩形被重置了颜色,而小矩形不变。
OpenCV中行列式相乘要求两个矩阵数据类型必须相同,且数据类型是CV_32FC1、 CV_64FC1、 CV_32FC2、 CV_64FC2之一。
相乘与顺序有关,这点与行列式乘法规则一样。ab与ba是完全不同的。
/* OpenCV行列式相乘,通道1*通道1 - 通道2*通道2 = 通道1
通道1*通道2 + 通道2*通道1 = 通道2*/
#include
#include
#include
#include
#include
int main()
{
cv::Mat a(2, 3, CV_32FC2);
cv::Mat b(3, 2, CV_32FC2);
cv::Mat img(2, 2, CV_32FC2);
for (int i = 0; i != 2; ++i)
{
for (int j = 0; j != 3; ++j)
{
a.at<cv::Vec2f>(i, j) = cv::Vec2f(i + j, 1);
}
}
int count = 0;
for (int i = 0; i != 3; ++i)
{
for (int j = 0; j != 2; ++j)
{
b.at<cv::Vec2f>(i, j) = cv::Vec2f(++count, 1);
}
}
img = a*b;
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
图7是相乘结果示意图: