目录
1.Dyn_threshold 动态阈值
2.OpenCV实现
2.Emphasize图像锐化增强处理
3.select_shape()特征筛选
4.opencv访问遍历图像的每一个像素方法
5.Fill_up()区域填充算子
6.Area_Center()计算区域面积与中心坐标
7.sort_region()对区域进行排序
8.shape_trans()区域转换算子
9.opencv双阈值二值化---->Halcon的直方图双阈值二值化
10.Gray_range_rect()图像灰度增强预处理
1.opencv4.3.0与VS2019环境配置见:
https://blog.csdn.net/weixin_50016546/article/details/124770493
2.opencv4.3.0与QT5.14.2环境配置见:
QT5.14 [MSVC 2017编译版]与 OpenCV4.3.0 联编环境配置_NCUTer的博客-CSDN博客
read_image (Image,'1.png')
mean_image (Image,ImageMean,9,9)
*动态阈值,也叫局部阈值
dyn_threshold (Image, ImageMean, RegionDynThresh, 15, 'not_equal')
方案1:
void dynthreshold_referHalcon(cv::Mat &frame_gray, int ksize, int offset) //仿Halcon
{
cv::Mat srcMean;
cv::Mat RegionDynThresh;
//均值滤波
blur(frame_gray, srcMean, cv::Size(9, 9));
//动态阈值
RegionDynThresh = cv::Mat::zeros(frame_gray.size(), CV_8UC1);
DynThreshold(frame_gray, srcMean, RegionDynThresh, offset, Equal);
}
void DynThreshold(cv::Mat &src, cv::Mat &srcMean, cv::Mat &result, int offset, int LightDark)
{
//使用Opencv实现Halcon中的动态阈值
//src是原图,灰度图
//srcMean是平滑滤波之后的图
//最好不要把Offset这个变量设置为0,因为这样会导致最后找到太多很小的regions,而这基本上都是噪声。
//所以这个值最好是在5-40之间,值选择的越大,提取出来的regions就会越小。
int r = src.rows; //高
int c = src.cols; //宽
int Value = 0;
for (int i = 0; i < r; i++)
{
uchar *datasrc = src.ptr(i); //指针访问图像像素
uchar *datasrcMean = srcMean.ptr(i);
uchar *dataresult = result.ptr(i);
for (int j = 0; j < c; j++)
{
switch (LightDark)
{
case Light:
Value = datasrc[j] - datasrcMean[j];
if (Value >= offset)
{
dataresult[j] = 255;
}
break;
case Dark:
Value = datasrcMean[j] - datasrc[j];
if (Value >= offset)
{
dataresult[j] = 255;
}
break;
case Equal:
Value = datasrc[j] - datasrcMean[j];
if (Value >= -offset && Value <= offset)
{
dataresult[j] = 255;
}
break;
case Not_equal:
Value = datasrc[j] - datasrcMean[j];
if (Value < -offset || Value > offset)
{
dataresult[j] = 255;
}
break;
default:
break;
}
}
}
}
方案2:
enum ThresholdType
{
THRESHOLD_LIGHT, //明
THRESHOLD_DARK, //暗
THRESHOLD_EQUAL, //等于
THRESHOLD_NOT_EQUAL //不等于
};
//功能:使用局部阈值分割图像
//参数:
// src:输入图像
// pre:包含本地阈值的图像(一般可使用均值滤波后的图像)
// dst:输出图像
// offset:灰度偏移量(-255 ≤ offset ≤ 255)
// type:
// THRESHOLD_LIGHT(明): g_src ≥ g_pre + offset
// THRESHOLD_DARK(暗): g_src ≤ g_pre - offset
// THRESHOLD_EQUAL(等于): g_pre - offset ≤ g_src ≤ g_pre + offset
// THRESHOLD_NOT_EQUAL(不等于): g_pre - offset > g_src || g_src > g_pre + offset
//返回值:无
void dyn_threshold(Mat src, Mat pre, Mat &dst, int offset, ThresholdType type)
{
dst = Mat(src.size(), CV_8UC1, Scalar(0));
int pixelsCount = src.rows * src.cols;
for(int i = 0;i < pixelsCount; i++)
{
int g_src = src.data[i];
int g_pre = pre.data[i];
if (type == THRESHOLD_LIGHT)
{
if (g_src >= g_pre + offset)
dst.data[i] = 255;
}
else if (type == THRESHOLD_DARK)
{
if (g_src <= g_pre - offset)
dst.data[i] = 255;
}
else if (type == THRESHOLD_EQUAL)
{
if (g_src >= g_pre - offset && g_src <= g_pre + offset)
dst.data[i] = 255;
}
else if (type == THRESHOLD_NOT_EQUAL)
{
if (g_src < g_pre - offset || g_src > g_pre + offset)
dst.data[i] = 255;
}
}
}
Halcon算子: emphasize(img,outputimg,20,20,2)
void emphasize(const cv::Mat &input, cv::Mat &output, int MaskWidth, int MaskHeight, float Factor)
{
//公式res := round((orig - mean) * Factor) + orig
//等价于在MaskHeight、MaskWidth的空间内中心化后增加方差
cv::Mat mean;
//等价于求指定范围窗口内的均值
cv::blur(input, mean, cv::Size(MaskWidth, MaskHeight));
output.create(input.size(), input.type());
if (input.type() == CV_8UC1)
{
for (int i = 0; i < input.rows; i++)
{
const uchar *rptr = input.ptr(i);
uchar *mptr = mean.ptr(i);
uchar *optr = output.ptr(i);
for (int j = 0; j < input.cols; j++)
{
optr[j] = cv::saturate_cast(round((rptr[j] - mptr[j]) * Factor) + rptr[j] * 1.0f);
}
}
}
else if (input.type() == CV_8UC3)
{
for (int i = 0; i < input.rows; i++)
{
const uchar *rptr = input.ptr(i);
uchar *mptr = mean.ptr(i);
uchar *optr = output.ptr(i);
for (int j = 0; j < input.cols; j++)
{
//饱和转换 小于0的值会被置为0 大于255的值会被置为255
optr[j * 3] = cv::saturate_cast(round((rptr[j * 3] - mptr[j * 3]) * Factor) + rptr[j * 3] * 1.0f);
optr[j * 3 + 1] = cv::saturate_cast(round((rptr[j * 3 + 1] - mptr[j * 3 + 1]) * Factor) + rptr[j * 3 + 1] * 1.0f);
optr[j * 3 + 2] = cv::saturate_cast(round((rptr[j * 3 + 2] - mptr[j * 3 + 2]) * Factor) + rptr[j * 3 + 2] * 1.0f);
}
}
}
}
read_image (Image, '1.jpg')
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, Regions, 43, 120)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0.45, 1)
opencv实现:
方案1:
#include "stdafx.h"
#include
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
#define VP vector //用VP符号代替 vector
RNG rng (12345);
//带有上下限的threshold
void threshold2(Mat gray,Mat& thresh,int minvalue,int maxvalue)
{
Mat thresh1;
Mat thresh2;
threshold(gray,thresh1,43,255, THRESH_BINARY);
threshold(gray,thresh2,111,255,THRESH_BINARY_INV);
thresh = thresh1 & thresh2;
}
//寻找并绘制出联通区域
vector> connection2(Mat src,Mat& draw)
{
draw = Mat::zeros(src.rows,src.cols,CV_8UC3);
vector>contours;
findContours(src,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
for (int i=0;i> selectShapeArea(Mat src,Mat& draw,vector contours,int minvalue,int maxvalue)
{
vector> result_contours;
draw = Mat::zeros(src.rows,src.cols,CV_8UC3);
for (int i=0;iminvalue && countour_area contour)
{
Point2f center;
float radius = 0;
minEnclosingCircle((Mat)contour,center,radius);
//以最小外接圆半径作为数学期望,计算轮廓上各点到圆心距离的标准差
float fsum = 0;
float fcompare = 0;
for (int i=0;i> selectShapeCircularity(Mat src,Mat& draw,vector contours,float minvalue,float maxvalue)
{
vector> result_contours;
draw = Mat::zeros(src.rows,src.cols,CV_8UC3);
for (int i=0;i=minvalue && fcompare <=maxvalue)
{
result_contours.push_back(contours[i]);
}
}
for (int i=0;i>contours_connection;
vector>contours_area;
vector>contours_circle;
vector>contours_tmp;
//read_image (Image1, '1.jpg')
src = imread("1.jpg");
//rgb1_to_gray (Image1, GrayImage)
cvtColor(src,gray,COLOR_BGR2GRAY);
//threshold (GrayImage, Regions, 43, 111)
threshold2(gray,thresh,43,111);
//connection (Regions, ConnectedRegions)
contours_connection = connection2(thresh.clone(),draw_connection);
//select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
contours_area = selectShapeArea(thresh.clone(),draw_area,contours_connection,150,666);
//select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0.45, 1)
contours_circle = selectShapeCircularity(thresh.clone(),draw_circle,contours_area,1,6);
//显示结果
imshow("src",src);
imshow("thresh",thresh);
imshow("draw_connection",draw_connection);
imshow("draw_area",draw_area);
imshow("draw_circle",draw_circle);
waitKey();
}
方案2:
enum SelectShapeType
{
SELECT_AREA, //选中区域面积
SELECT_RECTANGULARITY, //选中区域矩形度
SELECT_WIDTH, //选中区域宽度(平行于坐标轴)
SELECT_HEIGHT, //选中区域高度(平行于坐标轴)
SELECT_ROW, //选中区域中心行索引
SELECT_COLUMN, //选中区域中心列索引
SELECT_RECT2_LEN1, //选中区域最小外接矩形的一半长度
SELECT_RECT2_LEN2, //选中区域最小外接矩形的一半宽度
SELECT_RECT2_PHI, //选中区域最小外接矩形的方向
SELECT_ELLIPSE_RA, //选中区域外接椭圆的长半轴
SELECT_ELLIPSE_RB, //选中区域外接椭圆的短半轴
SELECT_ELLIPSE_PHI //选中区域外接椭圆的方向
};
enum SelectOperation
{
SELECT_AND, //与
SELECT_OR //或
};
//功能:借助形状特征选择区域
//参数:
// src:输入图像
// dst:输出图像
// types:要检查的形状特征
// operation:各个要素的链接类型(与、或)
// mins:下限值
// maxs:上限值
//返回值:无
int select_shape(Mat src, Mat &dst,
vector types,
SelectOperation operation,
vector mins,
vector maxs)
{
if (!(types.size() == mins.size() && mins.size() == maxs.size()))
return 0;
int num = types.size();
dst = Mat(src.size(), CV_8UC1, Scalar(0));
vector> contours;
findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
int cnum = contours.size();
vector> selectContours;
for (int i = 0; i < cnum; i++)
{
bool isAnd = true;
bool isOr = false;
for (int j = 0; j < num; j++)
{
double mind = mins[j];
double maxd = maxs[j];
if (mind > maxd)
{
mind = maxs[j];
maxd = mins[j];
}
if (types[j] == SELECT_AREA)
{
Mat temp = Mat(src.size(), CV_8UC1, Scalar(0));
vector> pconver;
pconver.push_back(contours[i]);
drawContours(temp, pconver, -1, Scalar(255), CV_FILLED);
bitwise_and(src, temp, temp);
int area;
Point2f center;
area_center(temp, area, center);
if (area >= mind && area <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_RECTANGULARITY)
{
Mat temp = Mat(src.size(), CV_8UC1, Scalar(0));
vector> pconver;
pconver.push_back(contours[i]);
drawContours(temp, pconver, -1, Scalar(255), CV_FILLED);
bitwise_and(src, temp, temp);
int area;
Point2f center;
area_center(temp, area, center);
RotatedRect rect = minAreaRect(contours[i]);
double rectangularity = area / rect.size.area();
if (rectangularity >= mind && rectangularity <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_WIDTH)
{
Rect rect = boundingRect(contours[i]);
if (rect.width >= mind && rect.width <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_HEIGHT)
{
Rect rect = boundingRect(contours[i]);
if (rect.height >= mind && rect.height <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_ROW)
{
Mat temp = Mat(src.size(), CV_8UC1, Scalar(0));
vector> pconver;
pconver.push_back(contours[i]);
drawContours(temp, pconver, -1, Scalar(255), CV_FILLED);
bitwise_and(src, temp, temp);
int area;
Point2f center;
area_center(temp, area, center);
if (center.y >= mind && center.y <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_COLUMN)
{
Mat temp = Mat(src.size(), CV_8UC1, Scalar(0));
vector> pconver;
pconver.push_back(contours[i]);
drawContours(temp, pconver, -1, Scalar(255), CV_FILLED);
bitwise_and(src, temp, temp);
int area;
Point2f center;
area_center(temp, area, center);
if (center.x >= mind && center.x <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_RECT2_LEN1)
{
RotatedRect rect = minAreaRect(contours[i]);
double len = rect.size.width;
if (rect.size.width < rect.size.height)
len = rect.size.height;
if (len / 2 >= mind && len / 2 <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_RECT2_LEN2)
{
RotatedRect rect = minAreaRect(contours[i]);
double len = rect.size.height;
if (rect.size.width < rect.size.height)
len = rect.size.width;
if (len / 2 >= mind && len / 2 <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_RECT2_PHI)
{
RotatedRect rect = minAreaRect(contours[i]);
float angle = 0;
if (angle < 0) angle += 180;
if (rect.size.width < rect.size.height)
{
angle = rect.angle;
angle -= 90;
if (angle < 0) angle += 180;
}
else
{
angle = rect.angle;
}
if (angle >= mind && angle <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_ELLIPSE_RA)
{
if (contours[i].size() < 5)
{
isAnd &= false;
isOr |= false;
continue;
}
RotatedRect rect = cv::fitEllipse(contours[i]);
double len = rect.size.width;
if (rect.size.width < rect.size.height)
len = rect.size.height;
if (len / 2 >= mind && len / 2 <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_ELLIPSE_RB)
{
if (contours[i].size() < 5)
{
isAnd &= false;
isOr |= false;
continue;
}
RotatedRect rect = cv::fitEllipse(contours[i]);
double len = rect.size.height;
if (rect.size.width < rect.size.height)
len = rect.size.width;
if (len / 2 >= mind && len / 2 <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
else if (types[j] == SELECT_ELLIPSE_PHI)
{
if (contours[i].size() < 5)
{
isAnd &= false;
isOr |= false;
continue;
}
RotatedRect rect = cv::fitEllipse(contours[i]);
float angle = 0;
if (angle < 0) angle += 180;
if (rect.size.width < rect.size.height)
{
angle = rect.angle;
angle -= 90;
if (angle < 0) angle += 180;
}
else
{
angle = rect.angle;
}
if (angle >= mind && angle <= maxd)
{
isAnd &= true;
isOr |= true;
}
else
{
isAnd &= false;
isOr |= false;
}
}
}
if (isAnd && operation == SELECT_AND)
selectContours.push_back(contours[i]);
if (isOr && operation == SELECT_OR)
selectContours.push_back(contours[i]);
}
drawContours(dst, selectContours, -1, Scalar(255), CV_FILLED);
bitwise_and(src, dst, dst);
return selectContours.size();
}
void method_1(Mat &image) {
double t1 = getTickCount();
int w = image.cols;
int h = image.rows;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
Vec3b bgr = image.at(row, col);
bgr[0] = 255 - bgr[0];
bgr[1] = 255 - bgr[1];
bgr[2] = 255 - bgr[2];
image.at(row, col) = bgr;
}
}
double t2 = getTickCount();
double t = ((t2 - t1) / getTickFrequency()) * 1000;
ostringstream ss;
ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
putText(image, ss.str(), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2, 8);
imshow("result", image);
}
//功能:填充区域中的孔洞
//参数:
// src:输入图像
// dst:输出图像
//返回值:无
void fill_up(Mat src, Mat &dst)
{
dst = Mat(src.size(), CV_8UC1, Scalar(0));
vector> contours;
findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(dst, contours, -1, Scalar(255), CV_FILLED);
}
//功能:求图中像素值为255的斑块面积和重心坐标
//参数:
// src:输入图像
// area:图中像素值为255的像素个数
// center:斑块的重心坐标
//返回值:无
void area_center(Mat src, int &area, Point2f ¢er)
{
int pixelsCount = src.rows * src.cols;
area = 0;
center = Point2f(0, 0);
float centerX = 0;
float centerY = 0;
int mcol = src.cols;
for(int i=0;i 0)
{
centerX /= area;
centerY /= area;
center = Point2f(centerX, centerY);
}
}
enum SortCriterion
{
FIRST_POINT, //区域第一行的最左侧的点
LAST_POINT, //区域最后一行的最右侧的点
UPPER_LEFT, //区域周围矩形的左上角
UPPER_RIGHT, //区域周围矩形的右上角
LOWER_LEFT, //区域周围矩形的左下角
LOWER_RIGHT //区域周围矩形的右下角
};
enum SortDirection
{
ROW, //区域按行排列,即从左到右,从上到下
COLUMN //区域按列排列,即从上到下,从左到右
};
//功能:由区域的相对位置对区域进行排序
//参数:
// src:输入图像
// contours:输入图像中的轮廓组
// pos:已排序的轮廓索引
// sc:排序基准点
// isDue:
// true:从小到大进行排序
// false:从大到小进行排序
// sd:排序方向
//返回值:true:排序成功
// false:排序失败
bool sort_region(Mat src,vector> contours, vector &pos,
SortCriterion sc, bool isDue, SortDirection sd)
{
int count = contours.size();
pos.resize(count);
vector points;
for (int i = 0; i < count; i++)
{
pos[i] = i;
Rect rect = boundingRect(contours[i]);
if (sc == FIRST_POINT)
{
int row = rect.y;
for (int col = rect.x; col <= rect.x + rect.width; col++)
{
if (src.at(row, col) > 0)
{
points.push_back(Point(col, row));
break;
}
}
}
else if (sc == LAST_POINT)
{
int row = rect.y + rect.height;
for (int col = rect.x + rect.width; col >= rect.x; col--)
{
if (src.at(row, col) > 0)
{
points.push_back(Point(col, row));
break;
}
}
}
else if (sc == UPPER_LEFT)
points.push_back(rect.tl());
else if (sc == UPPER_RIGHT)
points.push_back(Point(rect.x + rect.width, rect.y));
else if (sc == LOWER_LEFT)
points.push_back(Point(rect.x, rect.y + rect.height));
else if (sc == LOWER_RIGHT)
points.push_back(rect.br());
}
int np = points.size();
if (np != count)
return false;
if (sd == ROW)
{
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - 1 - i; j++)
{
if (isDue)
{
if (points[j].y > points[j + 1].y)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
else
{
if (points[j].y < points[j + 1].y)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
}
}
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - 1 - i; j++)
{
if (points[j].y == points[j + 1].y)
{
if (isDue)
{
if (points[j].x > points[j + 1].x)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
else
{
if (points[j].x < points[j + 1].x)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
}
}
}
}
else if (sd == COLUMN)
{
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - 1 - i; j++)
{
if (isDue)
{
if (points[j].x > points[j + 1].x)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
else
{
if (points[j].x < points[j + 1].x)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
}
}
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - 1 - i; j++)
{
if (points[j].x == points[j + 1].x)
{
if (isDue)
{
if (points[j].y > points[j + 1].y)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
else
{
if (points[j].y < points[j + 1].y)
{
Point temp = points[j];
points[j] = points[j + 1];
points[j + 1] = temp;
int index = pos[j];
pos[j] = pos[j + 1];
pos[j + 1] = index;
}
}
}
}
}
}
return true;
}
enum ShapeTransType
{
SHAPETRANS_RECTANGLE, //平行于坐标轴的最小外接矩形
SHAPETRANS_CIRCLE, //最小外接圆
SHAPETRANS_CONVER //凸包
};
//功能:变换区域的形状
//参数:
// src:输入图像
// dst:输出图像
// type:变换形状
//返回值:无
void shape_trans(Mat src, Mat &dst, ShapeTransType type)
{
dst = Mat(src.size(), CV_8UC1, Scalar(0));
vector> contours;
findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
int n = contours.size();
for (int i = 0; i < n; i++)
{
if (type == SHAPETRANS_RECTANGLE)
{
Rect rect = boundingRect(contours[i]);
rectangle (dst, rect, Scalar(255), CV_FILLED);
}
else if (type == SHAPETRANS_CIRCLE)
{
Point2f center;
float radius;
minEnclosingCircle(contours[i], center, radius);
circle (dst, center, radius, Scalar(255), CV_FILLED);
}
else if (type == SHAPETRANS_CONVER)
{
vector conver;
convexHull(contours[i], conver);
vector> pconver;
pconver.push_back(conver);
fillPoly(dst, pconver, Scalar(255));
}
}
}
halcon算子:
threshold(img , region , 40 , 160 )
//正向阈值二值化与反向阈值二值化按位与操作取交集
Mat src= imread("1.png");
Mat m1, m2, dst;
threshold(src, m1, 40, 255, cv::THRESH_BINARY);
threshold(src, m2, 160, 255, cv::THRESH_BINARY_INV);
bitwise_and(m1, m2, dst);
//halcon gray_range_rect算子的C++实现
void gray_range_rect(Mat &src, Mat &dst, Size size)
{
//图像边界扩充
int hh = (size.height - 1) / 2;
int hw = (size.width - 1) / 2;
cv::Mat Newsrc;
cv::copyMakeBorder(src, Newsrc, hh, hh, hw, hw, cv::BORDER_REFLECT_101);//以边缘为轴,对称
dst = cv::Mat::zeros(src.rows, src.cols, src.type());
//遍历图像
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
//uchar srcValue = src.at(i, j);
int minValue = 255;
int maxValue = 0;
for (int k = 0; k < hh; k++)
{
for (int z = 0; z < hw; z++)
{
int srcValue = (int)Newsrc.at(i + k, j + z);
minValue = minValue > srcValue ? srcValue : minValue;
maxValue = maxValue > srcValue ? maxValue : srcValue;
}
}
uchar diffValue = (uchar)(maxValue - minValue);
dst.at(i, j) = diffValue;
}
}
}
后续学习更新。。