OpenCv基础(C++)
这种初始化通常用于:创建空白图像,初始化临时处理矩阵,准备存储三通道数据(如彩色图像)1,2,3可以看作是一个像素点。
1.图像读取与显示
#include<opencv2/opencv.hpp>
using namespace cv;
Mat src = imread("C:/Users/16385/Desktop/new/photo/1.jpg");//读取图像
Mat src = imread("C:/Users/16385/Desktop/new/photo/1.jpg",IMREAD_GRAYSCALE);
//将读取的图像转为灰色
imshow("输入图像", src);//展示图像
2.色彩空间转换
Mat gray, hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);//将image的RGB色彩空间转换为hsv色彩空间
cvtColor(image, gray, COLOR_BGR2GRAY);
imwrite("D:/hsv.png", hsv);//保存图片到D盘
imwrite("D:/gray.png", gray);
hsv色彩空间

inrange 检查输入图像中的每个像素,如果像素值位于指定的范围内,则在输出图像(或掩码)中对应位置的像素被设置为白色(或者说是255),否则被设置为黑色(0)
void QuickDemo::inrange_demo(Mat& image)
{
Mat hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);
Mat mask;
inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);
//imshow("mask", mask);
Mat redback=Mat::zeros(image.size(),image.type());
redback = Scalar(40, 40, 200);
bitwise_not(mask, mask);
imshow("mask", mask);
image.copyTo(redback, mask);
//copyTO的行为
//只在mask为白色的区域,将image的像素复制到redback。
//黑色区域保持不变(即保留红色背景)。
imshow("roi区域提取", redback);
}
3.创建空白图像
这种初始化通常用于:创建空白图像,初始化临时处理矩阵,准备存储三通道数据(如彩色图像)
Mat m3 = Mat::zeros(Size(512, 512), CV_8UC3);
//表示每个元素是 8 位无符号整数(0-255),并且每个像素有 3 个通道 8U C3
m3 = Scalar(0, 0, 255);//设置图像的色彩值
std::cout << "width: " << m3.cols << "height: " << m3.rows << "channel: " << m3.channels() << std::endl;
//std::cout << m3 << std::endl;
imshow("图像", m3);
1,2,3可以看作是一个像素点
4.拷贝图像
Mat m4;
m3.copyTo(m4);//深拷贝(再创建一份空间,存储)
Mat m4=m3.clone();//深拷贝
Mat m4=m3;//浅拷贝(使用原来的空间,后续更改m4,m3也会更改)
5.图像的读写
//for循环读写
int w = image.cols;
int h = image.rows;
int dims = image.channels();
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (dims == 1)//灰度图像
{
int pv = image.at<uchar>(row, col);
image.at<uchar>(row, col) = 255 - pv;
}
if (dims == 3)//彩色图像
{
Vec3b bgr = image.at<Vec3b>(row, col);
image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}
imshow("像素图像",image);
//指针遍历,速度快
for (int row = 0; row < h; row++)
{
uchar* current = image.ptr<uchar>(row);//获取当前行指针
for (int col = 0; col < w; col++)
{
if (dims == 1)//灰度图像
{
int pv = *current;
*current++ = 255 - pv;//先索引,指针再++
}
if (dims == 3)//彩色图像
{
*current++ = 255 - *current;
*current++ = 255 - *current;
*current++ = 255 - *current;
}
}
}
6.图像像素的运算操作
Mat dst = Mat::zeros(image.size(),image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(5, 5, 5);
//运算后超过255,值会变成255,反之少于0,为0
add(image, m, dst);
subtract(image, m, dst);
multiply(image, m, dst);
divide(image, m, dst);
imshow("运算图像", dst);
7.滑块控件动态改变图像亮度
static void on_track(int b, void* userdata)
{
Mat image = *((Mat*)userdata);//先将void*指针强制转化为Mat*,再解引用得到image对象
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(b, b, b);
add(image, m, dst);
imshow("亮度调整", dst);
}
void QuickDemo::tracking_bar_demo(Mat& image)//引用传递是浅拷贝
{
namedWindow("亮度调整", WINDOW_AUTOSIZE);//创建窗口
//src = image;
int lightness = 50;
int max_value = 100;
createTrackbar("Value Bar:", "亮度调整", &lightness, max_value, on_track,(void*)(&image));//强制将&image转换为void*指针
on_track(50, &image);
}
8.键盘响应操作
void QuickDemo::key_demo(Mat& image)
{
Mat dst = Mat::zeros(image.size(), image.type());
while (true)
{
int c = waitKey(0);
if (c == 27) break;
if (c == 49)//键盘按下了数字1
{
std::cout << "press the number 1" << std::endl;
cvtColor(image, dst, COLOR_BGR2GRAY);
}
if (c == 50)//键盘按下了数字2
{
std::cout << "press the number 2" << std::endl;
cvtColor(image, dst, COLOR_BGR2HSV);
}
if (c == 51)//键盘按下了数字3
{
std::cout << "press the number 3" << std::endl;
dst = Scalar(50, 50, 50);
add(image, dst, dst);
}
imshow("图像", dst);
}
}
9.颜色表操作colormap,applyColorMap()
void QuickDemo::color_style_demo(Mat& image)
{
int colormap[]
{
COLORMAP_AUTUMN,
COLORMAP_BONE,
COLORMAP_JET,
COLORMAP_WINTER,
COLORMAP_RAINBOW,
COLORMAP_OCEAN,
COLORMAP_SUMMER,
COLORMAP_SPRING,
COLORMAP_COOL,
COLORMAP_HSV,
COLORMAP_PINK,
COLORMAP_HOT,
COLORMAP_PARULA,
COLORMAP_MAGMA,
COLORMAP_INFERNO,
COLORMAP_PLASMA,
COLORMAP_VIRIDIS,
COLORMAP_CIVIDIS,
COLORMAP_TWILIGHT,
COLORMAP_TWILIGHT_SHIFTED,
COLORMAP_TURBO,
COLORMAP_DEEPGREEN
};
Mat dst;
int index = 0;
while (true)
{
int c = waitKey(1000);
if (c == 27) break;
applyColorMap(image, dst, colormap[index]);
index=(++index)%22;
imshow("hh", dst);
}
}
10.图像像素运算(bitwise)
void QuickDemo::bitwise_demo(Mat& image)
{
Mat m1 = Mat::zeros(Size(255, 255), CV_8UC3);
Mat m2 = Mat::zeros(Size(255, 255), CV_8UC3);
rectangle(m1, Rect(100, 100, 80, 80), Scalar(0, 255, 255),-1);
rectangle(m2, Rect(150, 150, 80, 80), Scalar(255, 255, 0),-1);
imshow("m1", m1);
imshow("m2", m2);
Mat dst=m1^m2;//等价于bitwise_xor(m1, m2, dst);
//bitwise_or(m1, m2, dst);
//bitwise_and(m1, m2, dst);
//bitwise_not(image, dst);
imshow("hh", dst);
}
11.通道分离、合并、混合
void QuickDemo::channels_demo(Mat& image)
{
std::vector<Mat> mv;
split(image, mv);//分离通道
//imshow("blue", mv[0]);//opencv设置单通道只显示灰度图(黑白)
//imshow("green", mv[1]);
//imshow("red", mv[2]);
Mat dst;
mv[1] = 0;//只显示两个通道的颜色
merge(mv, dst);
imshow("merge", dst);
int from_to[] = { 0,2,1,1,2,0 };
/* src颜色通道0复制到dst颜色通道2
src颜色通道1复制到dst颜色通道1
src颜色通道2复制到dst颜色通道0*/
mixChannels(image, dst, from_to, 3);//通道混合
imshow("mix", dst);
}
12.图像像素最大值,最小值,平均值,标准差(minMaxLoc,meanStdDev)
void QuickDemo::pixel_statistic_demo(Mat& image)
{
double minv, maxv;
Point minLoc, maxLoc;
std::vector<Mat> mv;
split(image, mv);
for (int i = 0; i < 3; i++)
{
minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc);//这里需要使用mv的单通道
std::cout << "i:" << i << "minv= " << minv << "maxv= " << maxv << std::endl;
}
Mat mean, stddev;
meanStdDev(image, mean, stddev);
std::cout << "mean: " << mean << std::endl;
std::cout << "stddev: " << stddev << std::endl;
}
13.图像几何形状绘制
void QuickDemo::drawing_demo(Mat& image)
{
rectangle(image, Rect(100, 100, 250, 300), Scalar(0, 0, 255),1, LINE_AA,0);
circle(image, Point(100, 100), 50, Scalar(255, 0, 0),-1);
line(image, Point(100, 100), Point(200, 200), Scalar(0, 255, 0),5,8,0);
ellipse(image, RotatedRect(Point(200, 200), Size(50, 100), 90),Scalar(0,0,255),1, LINE_AA);
Mat dst;
dst = Mat::zeros(image.size(), image.type());
dst = Scalar(0, 255, 0);
addWeighted(image, 0.7, dst, 0.3,50,dst);
//addWeighted() 函数用于实现两个图像的加权融合(线性混合)
imshow("draw", dst);
}
14.随机数
// 方法1:使用默认种子(系统时间)
cv::RNG rng; // 等价于 cv::RNG rng(time(NULL));
// 方法2:指定种子(生成可重复的随机序列)
cv::RNG rng(12345); // 固定种子,每次运行生成相同的随机数
//指定种子后,假如第一次随机的是生成的随机数序列:85 22 91 14 67
//重置种子后再次生成:85 22 91 14 67
void QuickDemo::random_drawing()
{
Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
RNG rng(12345);//创建对象,12345是固定种子
while (true)
{
int c = waitKey(100);
if (c == 27) break;
int x1 = rng.uniform(0, canvas.cols);
int y1 = rng.uniform(0, canvas.rows);
int x2 = rng.uniform(0, canvas.cols);
int y2 = rng.uniform(0, canvas.rows);
//canvas = Scalar(0, 0, 0);可以每次使窗口变为黑色,每次窗口只显示一条线
line(canvas, Point(x1, y1), Point(x2, y2), Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
imshow("hh", canvas);
}
}
15.多边形填充与绘制
polylines();//绘制折线或轮廓
fillPoly();//填充多边形
drawContours();//绘制 / 填充轮廓
void QuickDemo::polyline_drawing_demo()
{
Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
Point p1(100, 100);
Point p2(350, 100);
Point p3(450, 280);
Point p4(320, 450);
Point p5(80, 400);
std::vector<Point>pts;
pts.push_back(p1);
pts.push_back(p2);
pts.push_back(p3);
pts.push_back(p4);
pts.push_back(p5);
polylines(canvas, pts, true, Scalar(255, 0, 0), 3, LINE_AA, 0);
fillPoly(canvas, pts, Scalar(0, 255, 0));
std::vector<std::vector<Point>> contours;
contours.push_back(pts);
drawContours(canvas, contours, -1, Scalar(0, 255, 0),-1);
imshow("hh", canvas);
}
16.鼠标操作与响应setMouseCallback
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_draw(int event, int x, int y, int flags, void* userdata)
{
Mat image = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN)
{
sp.x = x;
sp.y = y;
std::cout << sp << std::endl;
}
else if (event == EVENT_LBUTTONUP)
{
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0)
{
Rect box(sp.x, sp.y, dx,dy);
temp.copyTo(image);
imshow("ROI", image(box));//从image提取出box区域
rectangle(image, box, Scalar(0, 255, 0));
imshow("鼠标绘制", image);
sp.x = -1;
sp.y = -1;
}
}
else if (event == EVENT_MOUSEMOVE)
{
if (sp.x > 0 && sp.y > 0)
{
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0)
{
Rect box(sp.x, sp.y, dx, dy);
temp.copyTo(image);//覆盖原来的图像
rectangle(image, box, Scalar(0, 255, 0));
imshow("鼠标绘制", image);
}
}
}
}
void QuickDemo::mouse_drawing_demo(Mat& image)
{
namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
imshow("鼠标绘制", image);
temp = image.clone();
}
17.图像像素类型转换与归一化(normalize)
![]()

void QuickDemo::normal_demo(Mat& image)
{
Mat dst;
image.convertTo(image, CV_32F);//将图像转化为32位的浮点数
//这一步是必要的,因为归一化到 [0,1] 范围需要浮点数支持
normalize(image, dst, 1, 0, NORM_MINMAX);
imshow("hh", dst);
//OpenCV 的imshow函数在显示浮点数图像时,默认将 [0,1] 范围映射到 [0,255] 显示
}
18.图像缩放与插值(resize)
void QuickDemo::resize_demo(Mat& image)
{
Mat dst1,dst2;
int w = image.rows;
int h = image.cols;
resize(image, dst1, Size(w / 2, h / 2), 0, 0,INTER_LINEAR);
imshow("hh", dst1);
resize(image, dst2, Size(w * 1.2, h * 1.2), 0, 0, INTER_LINEAR);
imshow("hh1", dst2);
}
19.图像翻转flip
void QuickDemo::filp_demo(Mat& image)
{
Mat dst1,dst2,dst3;
flip(image, dst1, 0);//0:沿 X 轴(水平)翻转。
flip(image, dst2, 1);// 正数(如 1):沿 Y 轴(垂直)翻转。
flip(image, dst3, -1);//负数(如 - 1):同时沿 X 轴和 Y 轴翻转。
imshow("hh1", dst1);
imshow("hh2", dst2);
imshow("hh3", dst3);
}
20.图像旋转
Mat getRotationMatrix2D(Point2f center, double angle, double scale);
center:旋转中心点(图像坐标系中的坐标,例如Point2f(x, y))。angle:旋转角度(单位:度),正值表示逆时针旋转,负值表示顺时针旋转。scale:缩放因子(例如1.0表示保持原大小,0.5表示缩小一半)。
void warpAffine(InputArray src, OutputArray dst, InputArray M,
Size dsize, int flags=INTER_LINEAR,
int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
src:输入图像。dst:输出图像,大小由dsize指定,类型与输入图像相同。M:2×3 的变换矩阵(通常由getRotationMatrix2D或自定义方法生成)。
[ cosθ -sinθ 0 ]//M旋转时的矩阵
[ sinθ cosθ 0 ]
dsize:输出图像的大小(Size(width, height))。flags:插值方法,常用选项:INTER_LINEAR:双线性插值(默认)。INTER_NEAREST:最近邻插值。INTER_CUBIC:双三次插值(质量更高,但速度较慢)。
borderMode:边界填充模式,常用BORDER_CONSTANT(用常量填充)。borderValue:当borderMode为BORDER_CONSTANT时的填充值(默认黑色)。
旋转后的宽和高 的计算

void QuickDemo::rotato_demo(Mat& image)
{
Mat M, dst;
int w = image.cols;
int h = image.rows;
M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1);
double cos =abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
int nw = cos * w + sin * h;//新图像的尺寸
int nh = sin * w + cos * h;
M.at<double>(0, 2) += (nw / 2 - w / 2);//x轴偏移量
M.at<double>(1, 2) += (nh / 2 - h / 2);
warpAffine(image, dst, M, Size(nw, nh));
imshow("hh", dst);
}
21.视频文件摄像头的使用(VideoCapture)
void QuickDemo::vedio_demo()
{
VideoCapture v(0);//读取的使本地摄像头
Mat frame;
while (true)
{
v.read(frame);
if (frame.empty()) break;
imshow("hh", frame);
if (waitKey(1) == 27) break;
}
v.release();
}
void QuickDemo::vedio_demo()
{
VideoCapture v("C:/Users/16385/Desktop/new/photo/2.mp4");
int frame_width = v.get(CAP_PROP_FRAME_WIDTH);//获得v的相关信息
int frame_height = v.get(CAP_PROP_FRAME_HEIGHT);
int count = v.get(CAP_PROP_FRAME_COUNT);
double fps = v.get(CAP_PROP_FPS);
std::cout << "frame width:" << frame_width << std::endl;
std::cout << "frame height:" << frame_height << std::endl;
std::cout << "FPS:" << fps << std::endl;
std::cout << "Number of Frames:" << count << std::endl;
VideoWriter writer("D:/test.mp4", v.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);//保存视频
Mat frame;
while (true)
{
v.read(frame);
if (frame.empty()) break;
imshow("hh", frame);
writer.write(frame);
if (waitKey(1) == 27) break;
}
v.release();
writer.release();
}
22.图像直方图calcHist
23.单通道阈值处理threshold
double cv::threshold(
InputArray src, // 输入图像(单通道,8位/32位浮点型)
OutputArray dst, // 输出图像(与src尺寸、类型、通道数相同)
double thresh, // 设定的阈值
double maxval, // 阈值处理的最大值(仅对部分阈值类型有效)
int type // 阈值处理类型
);
| 类型常量 | 处理规则(dst(x,y) 为输出像素值,src(x,y) 为输入像素值) |
|---|---|
THRESH_BINARY |
若 src(x,y) > thresh,则 dst(x,y) = maxval;否则为 0 |
THRESH_BINARY_INV |
若 src(x,y) > thresh,则 dst(x,y) = 0;否则为 maxval |
THRESH_TRUNC |
若 src(x,y) > thresh,则 dst(x,y) = thresh;否则保持原值 |
THRESH_TOZERO |
若 src(x,y) > thresh,则保持原值;否则为 0 |
THRESH_TOZERO_INV |
若 src(x,y) > thresh,则为 0;否则保持原值 |
// 阈值检测 (抓取彩虹边)
Mat mask;
threshold(s_channel, mask, 90, 255, THRESH_BINARY);
24.腐蚀膨胀morphologyEx
这个函数需要先设置kernel
kernel = getStructuringElement(MORPH_RECT, Size(15, 5));
void cv::morphologyEx(
InputArray src, // 输入图像(单通道/多通道,8位/32位浮点型)
OutputArray dst, // 输出图像(与src尺寸、类型、通道数完全一致)
int op, // 形态学操作类型
InputArray kernel, // 结构化元素(由getStructuringElement生成)
Point anchor = Point(-1,-1), // 锚点位置(默认中心)
int iterations = 1, // 操作执行次数(默认1次)
int borderType = BORDER_CONSTANT, // 边界填充类型
const Scalar& borderValue = morphologyDefaultBorderValue() // 边界填充值
);
morphologyEx(mask, mask, MORPH_CLOSE, kernel);
| 操作常量 | 中文名称 | 底层运算逻辑 | 核心作用 |
|---|---|---|---|
MORPH_ERODE |
腐蚀 | 仅执行腐蚀操作 | 缩小亮区域、消除小的亮噪声点 |
MORPH_DILATE |
膨胀 | 仅执行膨胀操作 | 扩大亮区域、填补亮区域内的小黑洞 |
MORPH_OPEN |
开运算 | 腐蚀 → 膨胀 | 消除小的亮噪声、分离相邻的亮区域(去噪) |
MORPH_CLOSE |
闭运算 | 膨胀 → 腐蚀 | 消除亮区域内的小黑洞、连接相邻的亮区域 |
MORPH_GRADIENT |
形态学梯度 | 膨胀结果 - 腐蚀结果 | 提取图像边缘(轮廓) |
MORPH_TOPHAT |
顶帽(礼帽) | 原图 - 开运算结果 | 提取图像中比周围亮的小区域(如小亮点) |
MORPH_BLACKHAT |
黑帽 | 闭运算结果 - 原图 | 提取图像中比周围暗的小区域(如小黑洞) |
MORPH_HITMISS |
击中击不中 | 仅适用于二值图像(CV_8U),匹配特定像素邻域模式 | 检测图像中特定形状的小目标 |
25.寻找轮廓findContours
void cv::findContours(
InputArray image, // 输入图像(二值图,单通道8位)
OutputArrayOfArrays contours, // 输出轮廓集合
OutputArray hierarchy, // 输出轮廓的层级关系(可选)
int mode, // 轮廓检索模式
int method, // 轮廓逼近方法
Point offset = Point() // 轮廓点坐标的偏移量(可选)
);
findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
轮廓检索模式(mode 取值)
| 模式常量 | 说明 |
|---|---|
RETR_EXTERNAL |
仅检索最外层轮廓(忽略嵌套轮廓),层级 hierarchy 中所有元素为 -1;最常用(如只检测目标的外边缘)。 |
RETR_LIST |
检索所有轮廓,不建立层级关系(所有轮廓同级);速度快,无需区分父子轮廓时使用。 |
RETR_CCOMP |
检索所有轮廓,建立两层层级:外层轮廓为第 1 层,内层孔洞轮廓为第 2 层。 |
RETR_TREE |
检索所有轮廓,建立完整的层级树(保留所有嵌套 / 父子关系);最全面,但计算量稍大。 |
RETR_FLOODFILL |
基于泛洪填充的轮廓检索(较少用)。 |
轮廓逼近方法(method 取值)
| 方法常量 | 说明 |
|---|---|
CHAIN_APPROX_NONE |
存储轮廓上所有点(无压缩);优点:轮廓最完整;缺点:占用内存大。 |
CHAIN_APPROX_SIMPLE |
压缩轮廓点(仅保留拐点):如矩形仅存储 4 个角点;最常用(节省内存,不影响形状分析)。 |
CHAIN_APPROX_TC89_L1 / CHAIN_APPROX_TC89_KCOS |
基于 Teh-Chin 链逼近算法的优化压缩(精度更高,较少用)。 |
找到轮廓之后常用的函数
contourArea
计算单个轮廓面积的轻量级函数
boundingRect
计算单个轮廓的轴对齐外接矩形(矩形边平行于图像坐标轴),返回矩形的左上角坐标、宽度和高度
26.模板匹配Template Matching
void cv::matchTemplate(
InputArray image, // 输入图像(待搜索的源图像)
InputArray templ, // 模板图像(需匹配的小图像)
OutputArray result, // 输出匹配结果矩阵(相似度图)
int method, // 匹配方法
InputArray mask = noArray() // 模板掩码(可选,仅特定方法支持)
);
matchTemplate(source, templ, match_result, TM_CCOEFF_NORMED);
method可选
匹配方法(核心参数),决定相似度计算规则,OpenCV 定义的常量及含义如下:▫️ TM_SQDIFF:平方差匹配,值越小匹配度越高(0 为完全匹配);
▫️ TM_SQDIFF_NORMED:归一化平方差匹配,值范围 [0,1],0 为完全匹配;
▫️ TM_CCORR:相关匹配,值越大匹配度越高;
▫️ TM_CCORR_NORMED:归一化相关匹配,值范围 [0,1],1 为完全匹配;
▫️ TM_CCOEFF:相关系数匹配,值越大匹配度越高(最大值 1,最小值 -1);▫️ TM_CCOEFF_NORMED:归一化相关系数匹配,值范围 [-1,1],1 为完全匹配。
| 参数名称 (宏定义) | 中文名称 | 最佳匹配值 | 计算原理 (通俗版) | 适用场景 | 你的项目适用性 |
| TM_SQDIFF | 平方差匹配 | 0 (最小值) | 像素点对点相减,求平方和。越小代表越接近。 | 模板与原图是从同一幅图截取的,且光照完全一致。 | ❌ 不推荐 (R/B通道像素值差异大,误差会很大) |
| TM_SQDIFF_NORMED | 归一化平方差 | 0 (最小值) | 在 SQDIFF 基础上除以数值总和,进行归一化。 | 同上,但对整体亮度变化有一定抵抗力。 | ⭐ 勉强可用 (但不如 CCOEFF 准确) |
| TM_CCORR | 相关匹配 | 极大值 | 像素点对点相乘。数值越大代表重叠部分的能量越大。 | 几乎不用,因为它只偏爱亮斑,不考虑图像结构。 | ❌ 极差 (会误匹配到图像中最亮的地方) |
| TM_CCORR_NORMED | 归一化相关匹配 | 1 (最大值) | 相关匹配除以模长。 | 简单的模式识别,计算比 CCOEFF 快。 | ⚠️ 一般 (对纹理的区分度不如 CCOEFF) |
| TM_CCOEFF | 相关系数匹配 | 极大值 | 减去均值后进行相关运算。比较的是“相对明暗关系”。 | 光照变化较大的场景。 | ⭐ 可用 (但数值范围不固定,难设定阈值) |
| TM_CCOEFF_NORMED | 归一化相关系数 | 1 (最大值) | 减去均值 + 除以方差。结果固定在 -1 到 1 之间。 | 最复杂、最精准。抗光照、抗对比度变化能力最强。 | ✅ 最佳选择 (完美解决不同颜色通道间的差异) |
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)