🔆 文章首发于我的个人博客:欢迎大佬们来逛逛
🔆 OpenCV项目地址及源代码:点击这里
文章目录
- 图像截取
- 图像掩膜操作
图像截取
ROI操作,指的是:region of interest,感兴趣区域。
我们可以对一张图片的某个感兴趣的部分进行截取然后操作,这个截取的过程叫做**ROI
**操作。
通过三种方法实现ROI操作:
Rect
选定范围
Rect::Rect(int x, int y, int width, int height);
/*******************************************************************
* x: 左上角x坐标
* y: 左上角y坐标
* width: 宽度
* height: 高度
*********************************************************************/
Mat roi= img(Rect(x, y, w, h));
Range
选定范围
Range::Range(int _start, int _end) ;
/*******************************************************************
* _start: 起点
* _end: 终点
*********************************************************************/
Mat roi= img(Range(x,xx),Range(y,yy));
selectROI
专用API选择感兴趣区域,
Rect selectROI(InputArray img, bool showCrosshair = true, bool fromCenter = false);
/*******************************************************************
* img: 原图
* showCrosshair: 鼠标选框,是否显示十字线
* fromCenter: 是否以起始鼠标位置为中心
*********************************************************************/
//Rect rect= selectROI(img, false, false);
//1.显示img
//2.鼠标选择区域
//3.使用“空格”或“enter”来完成当前选择并开始一个新的选择,使用“esc”终止多个ROI选择过程
void selectROIs(const String& windowName, InputArray img,CV_OUT std::vector<Rect>& boundingBoxes, bool showCrosshair = true, bool fromCenter = false);
案例代码:
其中具有一个selectROIs的版本,可以让我们选择多个区域。
选择一个区域后按下回车,即可保存这个部分到一个std::vector<Rect>&
中,因此最终的全部选择的区域都在这个Rect的容器中。
其中我们选择好区域后,在使用Mat
重载的()
运算符即可做到在这张图片中截取一部分:
原型如下:
Mat operator()( Range rowRange, Range colRange ) const;
Mat operator()( const Rect& roi ) const
#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
#include <map>
class testROI {
public:
testROI() :mt(cv::imread("dog.png")) {}
void show(const std::string& title = "原图") {
for (auto& x : save) {
cv::imshow(x.first, x.second);
}
cv::waitKey(0);
}
void testRect(int x = 50, int y = 0, int w = 200, int h = 200) {
save["rect"] = mt(cv::Rect(x, y, w, h));
}
void testRange(int x = 50, int y = 0, int w = 200, int h = 200) {
save["range"] = mt(cv::Range(x, x + h), cv::Range(y, y + w));
}
void testSelect() {
save["select"] = mt(cv::selectROI(mt,false,false));
}
void testSelect2(const std::string& windowName) {
std::vector<cv::Rect> mts;
cv::selectROIs(windowName, mt, mts, false, false);
char name = 'a';
for (auto& x : mts) {
save[std::to_string(name)] = mt(x);
name += 1;
}
}
private:
cv::Mat mt;
std::map<std::string, cv::Mat> save;
};
int main() {
testROI* roi = new testROI();
//roi->testRange();
//roi->testRect();
//roi->testSelect();
cv::namedWindow("dog");
roi->testSelect2("dog");
roi->show();
return 0;
}
图像掩膜操作
掩膜操作指的是:用一个矩阵和原图像进行卷积运算,重新计算像素值。
因此我们需要定义一个权重表:
- 掩膜矩阵
- 计算公式
掩膜操作可以提高图像的对比度,对比度提高可以增加图像感官度、锐化,让看起来有点模糊的图像更清晰。
使用以下公式可以提高图像的对比度:
F ( i , j ) = 5 ∗ F ( i , j ) − F ( i − 1 , j ) − F ( i + 1 , j ) − F ( i , j − 1 ) − F ( i , j + 1 ) F(i,j) = 5*F(i,j)-F(i-1,j)-F(i+1,j)-F(i,j-1)-F(i,j+1) F(i,j)=5∗F(i,j)−F(i−1,j)−F(i+1,j)−F(i,j−1)−F(i,j+1)
对于这个公式的掩膜矩阵可以表示成如下的形式:
因此我们在定义掩膜矩阵的时候就可以使用这个。
我们通过两种方式实现图片的掩膜操作:
-
filter2D
实现- 我们使用
Mat_
来创建一个指定为3*3
的掩膜矩阵,并且完成赋值。 - 接着使用
filter2D
来实现操作。
//定义掩膜矩阵 Mat dst; Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); filter2D(img, dst, img.depth(), kernel); /******************************************************************* * img: 原图 * dst: 存储结果图 * img.depth(): 原图深度 * kernel: 掩膜矩阵 *********************************************************************/
- 我们使用
-
像素点实现,即对每个像素点执行上面的公式计算。
完整代码实现:
- testFilter2D 使用 filter2D完成掩膜计算。
- testPixel 使用像素点完成掩膜计算。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <map>
class Mask {
public:
Mask()
:mt(cv::imread("dog.png")) {
saves["origin"] = mt;
}
void testFilter2D() {
//API
cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cv::filter2D(mt, saves["mask"], mt.depth(), kernel);
}
void testPixel() {
saves["pixel"] = cv::Mat::zeros(mt.size(), mt.type());
int dims = mt.channels();
int rows = mt.rows - 1;
int cols = (mt.cols - 1) * dims;
for (int i = 1; i < rows ; i++) {
uchar* pre = mt.ptr<uchar>(i - 1); //ptr获取某一行,pre指前一行
uchar* next = mt.ptr<uchar>(i + 1); //next指下一行
uchar* cur = mt.ptr<uchar>(i); //cur是当前行
uchar* output = saves["pixel"].ptr<uchar>(i); //对当前行操作
for (int j = dims; j < cols; j++) { //
output[j] = cv::saturate_cast<uchar>(5 * cur[j] - pre[j] - next[j] - cur[j - dims] - cur[j + dims]);
}
}
}
void show() {
for (auto& x : saves) {
cv::imshow(x.first, x.second);
}
cv::waitKey(0);
}
private:
cv::Mat mt;
std::map<std::string, cv::Mat> saves;
};
int main()
{
Mask* pmask = new Mask();
pmask->testFilter2D();
pmask->testPixel();
pmask->show();
return 0;
}