一.阈值操作
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 读取灰度图像
cv::Mat src = cv::imread("image.png", cv::IMREAD_GRAYSCALE);
// 检查图像是否成功加载
if (src.empty()) {
std::cerr << "Error: Could not load input image." << std::endl;
return -1;
}
// 创建用于存储结果的图像
cv::Mat dst_binary, dst_binary_inv, dst_trunc, dst_tozero, dst_tozero_inv;
// 设置阈值和最大值
double thresh = 127;
double max_value = 255;
// 应用不同的阈值类型
cv::threshold(src, dst_binary, thresh, max_value, cv::THRESH_BINARY);
cv::threshold(src, dst_binary_inv, thresh, max_value, cv::THRESH_BINARY_INV);
cv::threshold(src, dst_trunc, thresh, max_value, cv::THRESH_TRUNC);
cv::threshold(src, dst_tozero, thresh, max_value, cv::THRESH_TOZERO);
cv::threshold(src, dst_tozero_inv, thresh, max_value, cv::THRESH_TOZERO_INV);
// 显示结果
cv::imshow("Original Image", src);
cv::imshow("Binary Threshold", dst_binary);
cv::imshow("Binary Inverse Threshold", dst_binary_inv);
cv::imshow("Truncate Threshold", dst_trunc);
cv::imshow("To Zero Threshold", dst_tozero);
cv::imshow("To Zero Inverse Threshold", dst_tozero_inv);
cv::waitKey(0);
return 0;
}
-
第一种
-
cv::THRESH_BINARY:
- 如果像素值大于阈值,则设置为最大值,否则设置为0。
- 公式:
dst(x, y) = max_value if src(x, y) > thresh else 0
- 示例:
cv::threshold(src, dst, thresh, max_value, cv::THRESH_BINARY);
-
cv::THRESH_BINARY_INV:
- 如果像素值大于阈值,则设置为0,否则设置为最大值。
- 公式:
dst(x, y) = 0 if src(x, y) > thresh else max_value
- 示例:
cv::threshold(src, dst, thresh, max_value, cv::THRESH_BINARY_INV);
-
cv::THRESH_TRUNC:
- 如果像素值大于阈值,则设置为阈值,否则保持原值。
- 公式:
dst(x, y) = thresh if src(x, y) > thresh else src(x, y)
- 示例:
cv::threshold(src, dst, thresh, max_value, cv::THRESH_TRUNC);
-
cv::THRESH_TOZERO:
- 如果像素值大于阈值,则保持原值,否则设置为0。
- 公式:
dst(x, y) = src(x, y) if src(x, y) > thresh else 0
- 示例:
cv::threshold(src, dst, thresh, max_value, cv::THRESH_TOZERO);
-
cv::THRESH_TOZERO_INV:
- 如果像素值大于阈值,则设置为0,否则保持原值。
- 公式:
dst(x, y) = 0 if src(x, y) > thresh else src(x, y)
- 示例:
cv::threshold(src, dst, thresh, max_value, cv::THRESH_TOZERO_INV);
第二种:copyTo
mask1.copyTo(mask_updated, mask2 > 0);
只有 mask2
中值大于 0 的位置,mask1
的值才会被复制到 mask_updated
中,其它位置保持不变。
第三种
mask.convertTo(lipid_mask, CV_8UC1, 85.0);
85.0
:缩放因子,即将 mask中的每个值乘以 85。
第四种
temp_mask.setTo(0, mask == 2);
字面意思 ,等于2的为0
二:计算最大面积
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(temp_mask, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
// 按轮廓面积排序,找到最大的轮廓
std::sort(contours.begin(), contours.end(), [](const std::vector<cv::Point>& a, const std::vector<cv::Point>& b) {
return cv::contourArea(a, false) > cv::contourArea(b, false);
});
-
std::sort(contours.begin(), contours.end(), ...)
:std::sort
是 C++ 标准库中的一个函数,用于对范围[contours.begin(), contours.end())
内的元素进行排序。contours
是一个std::vector<std::vector<cv::Point>>
类型的变量,其中每个元素是一个表示轮廓的点的向量。
-
[](const std::vector<cv::Point>& a, const std::vector<cv::Point>& b) { ... }
:- 这是一个 lambda 表达式,用作
std::sort
的比较函数。 - Lambda 表达式捕获列表为空(
[]
),表示不捕获任何外部变量。 - 它接受两个参数
a
和b
,这两个参数都是const std::vector<cv::Point>&
类型的引用,表示两个要比较的轮廓。
- 这是一个 lambda 表达式,用作
-
cv::contourArea(a, false)
和cv::contourArea(b, false)
:cv::contourArea
是 OpenCV 函数,用于计算轮廓的面积。a
和b
是两个轮廓。false
参数表示不计算轮廓的面积,默认为计算封闭区域的面积。
-
return cv::contourArea(a, false) > cv::contourArea(b, false);
:- 比较
a
和b
的面积。 - 如果
a
的面积大于b
的面积,则返回true
,否则返回false
。 - 这意味着
std::sort
会根据面积从大到小的顺序对轮廓进行排序
- 比较
三:生成随机颜色以及随机取点
// 将这些点打乱顺序
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(all_points_temp.begin(), all_points_temp.end(), g);
//随机取50个点作为跟踪参考
if (all_points_temp.size() > 50) {
all_points_temp.resize(50);
}
std::vector<cv::Scalar> m_colors;
cv::RNG rng(12345);
for (int i = 0; i < 1000; ++i) {
int r = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int b = rng.uniform(0, 256);
m_colors.push_back(cv::Scalar(b, g, r));
}
四:根据新点到旧点越来越粗画线
for (int i = feature_points.size() - 1; i > 0; --i) {
if (feature_points.size() < 2) {
continue;
}
bool p2Circle = (i + 1) >= feature_points.size();
draw_bgr_img = drawLines(draw_bgr_img, feature_points[i], feature_points[i - 1], p2Circle, mask, colorDeep);
colorDeep = std::pow(colorDeep, 1.8);
}
output_img = draw_bgr_img.clone();
cv::Mat maskLines = cv::Mat::zeros(bgr2.size(), bgr2.type());
for (size_t i = 0; i < p2.size(); ++i) {
cv::Point2f new_pt = p2[i];
cv::Point2f old_pt = p1[i];
cv::line(maskLines, new_pt, old_pt, m_colors[i] * colorDeep, 2);
if (p2Circle) {
cv::circle(maskLines, new_pt, 3, m_colors[i], -1);
}
}
if (!mask.empty()) {
maskLines.setTo(cv::Scalar(0, 0, 0), mask == 0);
}
cv::add(bgr2, maskLines, bgr2);
return bgr2;