opencv学习小结(9) – 利用拉普拉斯算子进行图像锐化

•利用3*3的Laplacian算子图象锐化:

•  Laplace函数实现的方法是先用Sobel 算子计算二阶x和y导数,再求和:

其基本函数模型如下:

Mat getLaplacian(Mat &Image)
{
  Mat Scr_Gray,showImage;
  int kernel_size = 3;
  int scale = 1;
  int delta = 0;
  int ddepth = CV_16S;
  // 使用高斯滤波消除噪声
  GaussianBlur(Image, Image, Size(3, 3), 0, 0, BORDER_DEFAULT);
 
  // 转换为灰度图
  cvtColor(Image, Scr_Gray, CV_RGB2GRAY);
 
  // 使用Laplace函数
  Mat abs_dst;
  Laplacian(Scr_Gray, showImage, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);
  convertScaleAbs(showImage, abs_dst);
  return abs_dst;
}
 
int main()
{
        Mat srcImage_2 = imread("g14.tif");
        namedWindow("【原始图均鞭】", 1);
  imshow("【原始图均鞭】", srcImage_2);
   	/*********************对图像进行Laplacian算子***************************/
   Mat showImage;
   showImage = getLaplacian(srcImage_2);
   imshow("Laplacian【效果图均鞭均鞭均鞭】", showImage);
}

最后的应用例程如下所示:

int main()
{
  Mat srcImage = imread("1.jpg");
  Mat srcImage_1 = imread("g11.tif");
  Mat srcImage_2 = imread("g14.tif");
  if (!srcImage.data)
  {
    cout << "fail to load the image" << endl;
    return -1;
  }
  if (!srcImage_1.data)
  {
    cout << "fail to load the image_1" << endl;
    return -2;
  }	
 
  if (!srcImage_2.data)
  {
    cout << "fail to load the image_2" << endl;
    return -3;
  }
 
  //namedWindow("【原始图】", 1);
  //imshow("【原始图】", srcImage);
  /****************对图像加椒盐噪声,并进行中值滤波******************/
  //salt_noise(srcImage, 4000);
  //pepper_noise(srcImage, 4000);
  //imshow("【噪声图】", srcImage);
  //Mat Medical_showImage, Medical_showImage_1;
  //MedianFlitering(srcImage, Medical_showImage);
  //medianBlur(srcImage, Medical_showImage_1, 3);
  //imshow("自定义中值滤波处理后", Medical_showImage);
  //imshow("openCV自带的中值滤波", Medical_showImage_1);
  /*******************************************************************/
 
  /*********************对图像添加高斯噪声并进行高斯滤波**************/
   //Mat GaussianshowImage,GaussianshowImage_1;
   //GaussianshowImage_1 = addGaussianNoise(srcImage);
   //imshow("高斯噪声【效果图】", GaussianshowImage_1);
   //GaussianBlur(GaussianshowImage_1, GaussianshowImage, Size(3, 3), 1);
   //imshow("高斯滤波【效果图】", GaussianshowImage);
  /*******************************************************************/
 
  /*********************对图像进行椒盐化并进行均值滤波****************/
  //Mat image1(srcImage.size(), srcImage.type());
  //Mat image2;
  //salt_noise(srcImage, 4000);
  //pepper_noise(srcImage, 4000);
  //imshow("椒盐图【效果图】", srcImage);
  //AverFiltering(srcImage, image1);
  //blur(srcImage, image2, Size(3, 3));//openCV库自带的均值滤波函数
  //imshow("自定义均值滤波", image1);
  //imshow("openCV自带的均值滤波", image2);
  /*******************************************************************/
 
  /*********************对图像进行Sobel算子***************************/
  //Mat showImage, showImage_1;
  //showImage=getSobel(srcImage_2);
  //imshow("Sobel算子【效果图】", showImage);
  /*******************************************************************/
 
  /*********************对图像进行Scharr算子***************************/
  //Mat showImage;
  //showImage = getScharr(srcImage_2);
  //imshow("高通滤波【效果图】", showImage);
  /*******************************************************************/
 
  /*********************对图像进行Laplacian算子***************************/
  /* Mat showImage;
   showImage = getLaplacian(srcImage_2);
   imshow("Laplacian【效果图】", showImage);*/
   /*******************************************************************/
 
 
        //Mat showImage = getHistogramImage(srcImage);        //得到相应图片的直方图 小狮子
  //Mat showImage = getHistogram_Equalization(srcImage);//得到相应图片的直方图的均衡图 小狮子

  //imshow("【直方图】", showImage);
 
  //getHistogram_Stetch(srcImage);                     //得到直方图拉伸之后的图像
 
/**********************测试代码*****************/
  //Mat element = getStructuringElement(MORPH_RECT,Size(15,15));
  //Mat dstImage;
  //erode(srcImage, dstImage, element);
  //imshow("腐蚀操作【效果图】", dstImage);
 
  //blur(srcImage, dstImage,Size(7,7));
  //imshow("均值滤波【效果图】", dstImage);
 
  //Mat edge, grayImage;
  //cvtColor(srcImage, grayImage, CV_BGR2GRAY);
  //blur(grayImage, edge, Size(3, 3));
  //Canny(edge, edge, 3, 9, 3);
  //imshow("边缘检测【效果图】", edge);
/**********************************************/
  waitKey(0);
  return 0;
}

部分函数被注释了,想使用的话去掉注释即可

opencv学习小结(8)- 利用索贝尔分子进行图像锐化

本例利用3*3的Sobel算子对g11实施图象锐化

Sobel算子使用两个3*3的矩阵算子使用两个3*3的矩阵去和原始图片作卷积,分别得到横向G(x)和纵向G(y)的

//Sobel算子
Mat getSobel(Mat &Image)
{
  Mat dst_x, dst_y, dst;
  Sobel(Image, dst_x, CV_16S,1, 0, 3,1,1,BORDER_DEFAULT);
  convertScaleAbs(dst_x, dst_x);
  imshow("对X方向求导【效果图】", dst_x);
 
  Sobel(Image, dst_y, CV_16S,0, 1, 3,1,1, BORDER_DEFAULT);
  convertScaleAbs(dst_y, dst_y);
  imshow("对Y方向求导【效果图】", dst_y);
  addWeighted( dst_x, 0.5, dst_y, 0.5, 0, dst);
 
  return dst;
}
 
 
int main()
{
        Mat srcImage_2 = imread("g14.tif");
  namedWindow("【原始图】", 1);
  imshow("【原始图】", srcImage_2);
  /*********************对图像进行Sobel算子***************************/
  Mat showImage, showImage_1;
  showImage=getSobel(srcImage_2);
  imshow("Sobel算子【均鞭】", showImage);
}

 

梯度值,如果梯度值大于某一个阈值,则认为该点为边缘点。

 

 

效果图如下(这里我们直接显示x方向求偏导和对y方向上求的偏导的像素值)

 

 

opencv学习小结(7) – 使用中值滤波来平滑图像

中值滤波:我们可以讲中值滤波应用到图像处理中。依然,我们在图像中去3*3的矩阵,里面有9个像素点,我们将9个像素进行排序,最后将这个矩阵的中心点赋值为这九个像素的中值。

预处理图像

例程如下:

//求九个人形的中值
uchar Median(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,uchar n6, uchar n7, uchar n8, uchar n9) 
{
  uchar arr[9];
  arr[0] = n1;
  arr[1] = n2;
  arr[2] = n3;
  arr[3] = n4;
  arr[4] = n5;
  arr[5] = n6;
  arr[6] = n7;
  arr[7] = n8;
  arr[8] = n9;
  for (int gap = 9 / 2; gap > 0; gap /= 2)//希尔排序
    for (int i = gap; i < 9; ++i)
      for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
        swap(arr[j], arr[j + gap]);
  return arr[4];//返回中值
}
//中值滤波函数
void MedianFlitering(const Mat &src, Mat &dst) 
{
  if (!src.data)return;
  Mat _dst(src.size(), src.type());
  for (int i = 0; i < src.rows; ++i)
    for (int j = 0; j < src.cols; ++j)
    {
      if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols)
      {
        _dst.at<Vec3b>(i, j)[0] = Median(src.at<Vec3b>(i, j)[0], src.at<Vec3b>(i + 1, j + 1)[0],
          src.at<Vec3b>(i + 1, j)[0], src.at<Vec3b>(i, j + 1)[0], src.at<Vec3b>(i + 1, j - 1)[0],
          src.at<Vec3b>(i - 1, j + 1)[0], src.at<Vec3b>(i - 1, j)[0], src.at<Vec3b>(i, j - 1)[0],
          src.at<Vec3b>(i - 1, j - 1)[0]);
        _dst.at<Vec3b>(i, j)[1] = Median(src.at<Vec3b>(i, j)[1], src.at<Vec3b>(i + 1, j + 1)[1],
          src.at<Vec3b>(i + 1, j)[1], src.at<Vec3b>(i, j + 1)[1], src.at<Vec3b>(i + 1, j - 1)[1],
          src.at<Vec3b>(i - 1, j + 1)[1], src.at<Vec3b>(i - 1, j)[1], src.at<Vec3b>(i, j - 1)[1],
          src.at<Vec3b>(i - 1, j - 1)[1]);
        _dst.at<Vec3b>(i, j)[2] = Median(src.at<Vec3b>(i, j)[2], src.at<Vec3b>(i + 1, j + 1)[2],
          src.at<Vec3b>(i + 1, j)[2], src.at<Vec3b>(i, j + 1)[2], src.at<Vec3b>(i + 1, j - 1)[2],
          src.at<Vec3b>(i - 1, j + 1)[2], src.at<Vec3b>(i - 1, j)[2], src.at<Vec3b>(i, j - 1)[2],
          src.at<Vec3b>(i - 1, j - 1)[2]);
      }
      else
        _dst.at<Vec3b>(i, j) = src.at<Vec3b>(i, j);
    }
  _dst.copyTo(dst);//拷贝
}
 
int main()
{
        Mat srcImage = imread("1.jpg");
        namedWindow("我是小狮子.png", 1);
  imshow("我是小狮子.png", srcImage);
        /****************对图像加jiaoyan噪声,并进行中值滤波******************/
    	salt_noise(srcImage, 4000);
  pepper_noise(srcImage, 4000);
  imshow("我是小小小狮子.png", srcImage);
  Mat Medical_showImage, Medical_showImage_1;
  MedianFlitering(srcImage, Medical_showImage);
  medianBlur(srcImage, Medical_showImage_1, 3);
  imshow("自定义中值滤波处理后", Medical_showImage);
  imshow("openCV自带的中值滤波", Medical_showImage_1);
}

 

opencv学习小结(6)-模板匹配技术实现

模板匹配

今天我们开始来学习opencv的模板匹配函数,可以用来做快速二维码读入,或者别的信息读入。

模板匹配这是一项在一幅图中寻找与另一幅“模板”图像最匹配(相似)部分的技术,

这个方法应该是寻找ROI(模板)最简单高效的方式了。模板匹配的工作方式跟直方图的反向投影基本一样,只不过反射投影直方图得到的是ROI出现在图像中特定位置的概率,是一种概率映射,而模板匹配是直接关于像素的度量。

假设我们有一张100×100的输入input图像,ROI(模ro板)是10×10的output图像,那么模板匹配具体的操作可以由以下方式来实现

 

1)从输入图像的左上角(0,0)开始滑动,获取(0,0)至(10,10)的临时图像;
2)选择一种度量方式(函数)对比临时图像和模板图像,度量值 保存 到 结果图像矩阵 (R) 中;
3)滑动模板图像至(0,1),获取(0,1)至(10,11)的临时图像,对比,并将度量值记录到结果图像R中;
4)重复步骤(1)~(3)直到输入图像的右下角;
5)定位在结果图像矩阵 R 中的最大值点 (或者最小值, 根据度量函数输入的匹配参数),即为模板最有可能出现的位置。

 

在OpenCV中提供了模板匹配的API函数,其函数原型为:

void matchTemplate(InputArray image, 
                   InputArray templ, 
                   OutputArray result,  
                   int method)

 

这是我老婆小狮子:

output图像

前三个由操作步骤很容易理解,第四个参数是模板匹配的度量函数,OpenCV支持以下6种对比方式:
CV_TM_SQDIFF 平方差匹配法:采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR 相关匹配法:采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 归一化平方差匹配法
CV_TM_CCORR_NORMED 归一化相关匹配法
CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
具体公式请参考opencvdoc。

 

demo程序:

#ifndef SAT8_xiaoshizi
#define SAT8_xiaoshizi
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#endif

using namespace std;
using namespace cv;

bool draw;  
Mat src;//原始图像  
Mat roi;//ROI图像
Mat result;
Point cursor;//初始坐标   
Rect rect;//标记ROI的矩形框

char* image_window = "SrcImage";
char* result_window = "Result window";

int match_method;
int max_Trackbar = 5;

void MatchingMethod( int, void* );
void onMouse(int event, int x, int y, int flags, void *param);


int main()
{
    src=imread("sat8.jpg");
    if(src.data==0)
    {
        cout<<"error, the src image is not built!"<<endl;
        return -1;
    }
    //cvtColor(src,src,CV_BGR2GRAY);
    namedWindow(image_window);
    imshow(image_window,src);
    setMouseCallback(image_window, onMouse, NULL); 
    namedWindow(result_window);

    waitKey();
    return 0;
}

void onMouse(int event, int x, int y, int flags, void *param)  
{  
    Mat img = src.clone();
    switch (event)  
    { 
    //按下鼠标左键
    case CV_EVENT_LBUTTONDOWN:          
        //点击鼠标图像时,清除之前ROI(ro635)图像的显示窗口  
        cvDestroyWindow("ROI");   
        //存放起始坐标  
        cursor = Point(x, y);  
        //初始化起始矩形框  
        rect = Rect(x, y, 0, 0);  
        draw = true;  
        break;  

    //松开鼠标左键      
    case CV_EVENT_LBUTTONUP:           
        if (rect.height > 0 && rect.width > 0)  
        {  
            //将img中的矩形区域复制给roi,并显示在SignROI窗口 
            roi = img(Rect(rect.x, rect.y, rect.width, rect.height));  
            rectangle(img, rect, Scalar(0, 0, 255),2);  
            namedWindow("SignROI");  
            imshow("SignROI", img);  

            //将画过矩形框的图像用原图像还原  
            src.copyTo(img);  
            imshow("SrcImage", img);  

            //显示ROI图像
            //namedWindow("ROI");  
            //imshow("ROI", roi);    

            //进行模板匹配
            // 创建滑动条
            char* trackbar_label = "MatchTemplate"; /* 0: SQDIFF
                                             1: SQDIFF NORMED 
                                             2: TM CCORR
                                             3: TM CCORR NORMED
                                             4: TM COEFF 
                                             5: TM COEFF NORMED  */
            createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );

            MatchingMethod( 0, 0 );
            waitKey(10);  
        }  
        draw = false;  
        break;  

    //移动光标
    case CV_EVENT_MOUSEMOVE:  
        if (draw)
        {  
            //用MIN得到左上点作为矩形框的起始坐标,如果不加这个,画矩形时只能向一个方向进行  
            rect.x = MIN(x, cursor.x);  
            rect.y = MIN(y, cursor.y);  
            rect.width = abs(cursor.x - x);  
            rect.height = abs(cursor.y - y);  
            //防止矩形区域超出图像的范围  
            rect &= Rect(0, 0, src.cols, src.rows);  
        }  
        break;  
    }  
}  

void MatchingMethod( int, void* )
{
    // 将被显示的原图像
    Mat img_display;
    src.copyTo( img_display );

    // 创建输出结果的矩阵
    int result_cols =  src.cols - roi.cols + 1;
    int result_rows = src.rows - roi.rows + 1;

    result.create( result_cols, result_rows, CV_32FC1 );

    // 进行匹配和标准化
    matchTemplate( src, roi, result, match_method );
    normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );

    // 通过函数 minMaxLoc 定位最匹配的位置
    double minVal; double maxVal; Point minLoc; Point maxLoc;
    Point matchLoc;

    minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );

    // 对于方法 SQDIFF 和 SQDIFF_NORMED, 越小的数值代表更高的匹配结果
    //对于其他方法, 数值越大匹配越好
    if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    { 
        matchLoc = minLoc; 
    }
    else
    { 
        matchLoc = maxLoc; 
    }

    // 检测结果
    rectangle( img_display, matchLoc, Point( matchLoc.x + roi.cols , matchLoc.y + roi.rows ), Scalar::all(0), 2, 8, 0 );
    rectangle( result, matchLoc, Point( matchLoc.x + roi.cols , matchLoc.y + roi.rows ), Scalar::all(0), 2, 8, 0 );

    imshow( image_window, img_display );
    imshow( result_window, result );
    return;
}

opencv学习小结(5)- 使用高斯滤波来平滑图像

•对自备图片利用二维高斯模板,对其进行加权平滑滤波,并比较其效果

•高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程

高斯小狮子

程序如下:

//得到高斯小狮子噪声色色
double generateGaussianNoise(double mu, double sigma)
{
  //定义一个特别小的值
  const double epsilon = numeric_limits<double>::min();//返回目标数据类型能表示的最逼近1的正数和1的差的绝对值
  static double z0, z1;
  static bool flag = false;
  flag = !flag;
  //flag为假,构造高斯随机变量
  if (!flag)
    return z1 * sigma + mu;
  double u1, u2;
  //构造随机变量
 
  do
  {
    u1 = rand()*(1.0 / RAND_MAX);
    u2 = rand()*(1.0 / RAND_MAX);
  } while (u1 <= epsilon);
  //flag为真构造高斯随机变量X
  z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI * u2);
  z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI * u2);
  return z1 * sigma + mu;
}
//为图像添加高斯噪声
Mat addGaussianNoise(Mat& srcImage)
{
  Mat resultImage = srcImage.clone();    //深拷贝,克隆
  int channels = resultImage.channels();    //获取图像的通道
  int nRows = resultImage.rows;    //图像的行数
 
  int nCols = resultImage.cols*channels;   //图像的总列数
  //判断图像的连续性
  if (resultImage.isContinuous())    //判断矩阵是否连续,若连续,我们相当于只需要遍历一个一维数组 
  {
    nCols *= nRows;
    nRows = 1;
  }
  for (int i = 0; i < nRows; i++)
  {
    for (int j = 0; j < nCols; j++)
    {	//添加高斯噪声
      int val = resultImage.ptr<uchar>(i)[j] + generateGaussianNoise(2, 0.8) * 32;
      if (val < 0)
        val = 0;
      if (val > 255)
        val = 255;
      resultImage.ptr<uchar>(i)[j] = (uchar)val;
    }
  }
  return resultImage;
}
 
int main()
{
        Mat srcImage = imread("1.jpg");
        namedWindow("均鞭图", 1);
  imshow("均鞭图", srcImage);
  /*********************对图像添加高斯噪声并进行高斯滤波**************/
   Mat GaussianshowImage,GaussianshowImage_1;
   GaussianshowImage_1 = addGaussianNoise(srcImage);
   imshow("高斯噪声小狮子的色图", GaussianshowImage_1);
   GaussianBlur(GaussianshowImage_1, GaussianshowImage, Size(3, 3), 1);
   imshow("高斯滤波小狮子的色图", GaussianshowImage);
}

程序例程如上,可自行shiy

opencv学习小结-(4) 使用 均 值滤波来平滑图像

需要使用到该 库函数

CV_EXPORTS_W void blur( InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT );

均值滤波:线性平均滤波器,它通过求窗口内所有像素的平均值来得到中心像素点的像素值,就比如下图:

均值滤波示例程序如下:

//jun盐噪声
void salt_noise(Mat image, int n) 
{
 
  int i, j;
  for (int k = 0; k < n / 2; k++) {
 
    // rand() is the random number generator
    i = std::rand() % image.cols; // % 整除取余数运算符,rand=1022,cols=1000,rand%cols=22
    j = std::rand() % image.rows;
 
    if (image.type() == CV_8UC1) { // gray-level image
 
      image.at<uchar>(j, i) = 255; //at方法需要指定Mat变量返回值类型,如uchar等
 
    }
    else if (image.type() == CV_8UC3) { // color image
 
      image.at<cv::Vec3b>(j, i)[0] = 255; //cv::Vec3b为opencv定义的一个3个值的向量类型
      image.at<cv::Vec3b>(j, i)[1] = 255; //[]指定通道,B:0,G:1,R:2
      image.at<cv::Vec3b>(j, i)[2] = 255;
    }
  }
}
//椒噪声
void pepper_noise(Mat image, int n) 
{
 
  int i, j;
  for (int k = 0; k < n; k++) {
 
    // rand() is the random number generator
    i = std::rand() % image.cols; // % 整除取余数运算符,rand=1022,cols=1000,rand%cols=22
    j = std::rand() % image.rows;
 
    if (image.type() == CV_8UC1) { // gray-level image
 
      image.at<uchar>(j, i) = 0; //at方法需要指定Mat变量返回值类型,如uchar等
 
    }
    else if (image.type() == CV_8UC3) { // color image
 
      image.at<cv::Vec3b>(j, i)[0] = 0; //cv::Vec3b为opencv定义的一个3个值的向量类型
      image.at<cv::Vec3b>(j, i)[1] = 0; //[]指定通道,B:0,G:1,R:2
      image.at<cv::Vec3b>(j, i)[2] = 0;
    }
  }
}
 
//均值滤波
void AverFiltering(const Mat &src, Mat &dst) {
  if (!src.data) return;
  //at访问像素点
  for (int i = 1; i < src.rows; ++i)
    for (int j = 1; j < src.cols; ++j) {
      if ((i - 1 >= 0) && (j - 1) >= 0 && (i + 1) < src.rows && (j + 1) < src.cols) {//边缘不进行处理
        dst.at<Vec3b>(i, j)[0] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i - 1, j - 1)[0] + src.at<Vec3b>(i - 1, j)[0] + src.at<Vec3b>(i, j - 1)[0] +
          src.at<Vec3b>(i - 1, j + 1)[0] + src.at<Vec3b>(i + 1, j - 1)[0] + src.at<Vec3b>(i + 1, j + 1)[0] + src.at<Vec3b>(i, j + 1)[0] +
          src.at<Vec3b>(i + 1, j)[0]) / 9;
        dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i - 1, j - 1)[1] + src.at<Vec3b>(i - 1, j)[1] + src.at<Vec3b>(i, j - 1)[1] +
          src.at<Vec3b>(i - 1, j + 1)[1] + src.at<Vec3b>(i + 1, j - 1)[1] + src.at<Vec3b>(i + 1, j + 1)[1] + src.at<Vec3b>(i, j + 1)[1] +
          src.at<Vec3b>(i + 1, j)[1]) / 9;
        dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] + src.at<Vec3b>(i - 1, j - 1)[2] + src.at<Vec3b>(i - 1, j)[2] + src.at<Vec3b>(i, j - 1)[2] +
          src.at<Vec3b>(i - 1, j + 1)[2] + src.at<Vec3b>(i + 1, j - 1)[2] + src.at<Vec3b>(i + 1, j + 1)[2] + src.at<Vec3b>(i, j + 1)[2] +
          src.at<Vec3b>(i + 1, j)[2]) / 9;
      }
      else {//边缘赋值
        dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
        dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
        dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
      }
    }
}
 
int main()
{
        Mat srcImage = imread("1.jpg");
  namedWindow(".jpg", 1);
  imshow(".jpg", srcImage);
  /*********************对图像进行椒盐化并进行均值滤波****************/
  Mat image1(srcImage.size(), srcImage.type());
  Mat image2;
  salt_noise(srcImage, 4000);
  pepper_noise(srcImage, 4000);
  imshow("均鞭智能生成图像", srcImage);
  AverFiltering(srcImage, image1);
  blur(srcImage, image2, Size(3, 3));//openCV库自带的均值滤波函数
  imshow("自定义均值滤波", image1);
  imshow("openCV自带的均值滤波", image2);
}

opencv学习小结-3 直方图均衡化

均!

直方图均衡化

1.实质:通过某种映射关系,将直方图中较为集中的部分均衡化,较为均衡地分布

2. 利用cv2.equalizeHist(),直方图均衡化

3.彩色直方图均衡化,将图像矩阵拆分为各个单通道矩阵,分别均衡化后,再合并各通道矩阵。

 

#灰度-直方图均衡化
import cv2
 
grayImg = cv2.imread('image01.jpg',0)
cv2.imshow('src',grayImg)
 
dst = cv2.equalizeHist(grayImg)
 
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 彩色-直方图均衡化
import cv2
 
img = cv2.imread('image01.jpg',1)
cv2.imshow('src',img)
 
(b,g,r) = cv2.split(img)            # 通道拆分
 
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
 
result = cv2.merge((bH,gH,rH))      # 通道合并
cv2.imshow('dst',result)
cv2.waitKey(0)

 

opencv学习小结(2)-filter2D函数

函数原型:均

dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

 

参数 描述
src 原图像
dst 目标图像,与原图像尺寸和通过数相同
ddepth 目标图像的所需深度
kernel 卷积核(或相当于相关核),单通道浮点矩阵;如果要将不同的内核应用于不同的通道,请使用拆分将图像拆分为单独的颜色平面,然后单独处理它们。
anchor 内核的锚点,指示内核中过滤点的相对位置;锚应位于内核中;默认值(-1,-1)表示锚位于内核中心。
detal 在将它们存储在dst中之前,将可选值添加到已过滤的像素中。类似于偏置。
borderType 像素外推法,参见BorderTypes

改函数实际计算的是相关性,而不是卷积

在内核足够大(~11×11或者更大)的时候,该函数使用DFT算法,对于小内核则直接计算。

也可见,anchor相当于坐标轴平移。

其中ddepth表示目标图像的所需深度,它包含有关图像中存储的数据类型的信息,可以是unsigned char(CV_8U),signed char(CV_8S),unsigned short(CV_16U)等等…

Input depth (src.depth()) Output depth (ddepth)
CV_8U -1/CV_16S/CV_32F/CV_64F
CV_16U/CV_16S -1/CV_32F/CV_64F
CV_32F -1/CV_32F/CV_64F
CV_64F -1/CV_64F

Note:当ddepth=-1时,表示输出图像与原图像有相同的深度。

opencv学习小结(1)–高斯模糊与卷积核

因为做的项目需要用到opencv的工具包,所以本人就开始了对opencv的各类函数进行原理上的学习,希望能够尽快的完成对opencv系统的学习。

1:什么是高斯模糊:

模糊是一种利用图像算法对源图像素色值进行重新合成的一种处理结果(当然也是近视眼就会导致模糊..xixi),而高斯模糊则是运用高斯函数(遵循数据正态分布)求出对应图像的卷积核在进行一定换算最后合成图像的一种特殊处理结果,当然其中有很多过程及概念,先简单了解一下高斯模糊成像的过程是怎么样的:

1:卷积核:

一看非常高大上的名字,它其实就是通过某种算法得出的一个结果矩阵,我们知道图像其实就是一个二维的矩阵排列,通过高斯函数求出来的卷积核(矩阵)在与源矩阵进行一定的换算就得出结果矩阵就是我们最后模糊的图像结果,效果如图所示:

示例1

假设我们先不关心卷积核的生成,那么他是如何通过卷积核生成结果矩阵的呢:如图中所示:如果要求出结果矩阵的第2排第2列中的元素值需要将卷积核矩阵对准源矩阵中对应的像素元素也就是source pixel中的6(3*3的矩阵),然后通过求出加权的和也就是(-1*3)+(0*0)+(1*1)+(-2*2)+(0*6)+(2*2)+(-1*2)+(0*4)+(1*1)结果为-3,那么结果矩阵里的第2排第2列的元素值为-3;是不是感觉就是那么回事,其实的确就是那么回事,通过高斯函数求出的卷积核(也称滤波器)在进行加权求和就得出运算之后的图像了,那么现在知道模糊成像的这么一个过程,我们应该继续探索高斯求出的卷积核是怎么求出来的!

2:模糊的原理

我们知道了模糊的一个过程那么我们应该知道模糊的简单原理是什么样的还是画图理解更好解释:

示例2

如上图所示,如果我们想对中心元素点2进行一个模糊处理那么应该怎么做,既然是模糊那么就是通过周边元素的值来确定自己应该是多少,显然照上图来看的话我们模糊很简单就是求出周边的加权平均,结果就是1了(就像扫雷一样)

即(1+1+1+1+2+1+1+1+1)/9=1,如下:

示例3

这样得出的结果就已经是经过简单模糊的图像的了,当然实际操作不可能通过这么简单的运算来得出模糊图像,因为不管从效率还是实际的模糊效果来说都太差了,那么我们应该去学习更高级的权重分配模式了。在统计学里有一个影响深远的权重分配模式叫“正态分布”,在高斯模糊中也正是遵循正态分布来求出适应的模糊值,那么我们就了解一下正态分布是什么东西吧

正态分布的权重

一维的正态分布图
二维的正态分布图(图像都是二维)

首先我们来看一下正态分布是个什么样子,在统计学中正态分布应用在很多地方如医学,建筑等领域,从图中我们可以看出距离中心0zero的位置越小取值越大,曲度越大,处于中心点则是最高权重,位于周边则取值递减,也更加符合只有距离模糊像素越近的像素才有更高的权重思路,这种做法就避免了如果模糊像素与周边像素颜色差值过大造成的模糊效果不尽人意的问题;

权重矩阵(可以理解为卷积核)

如果理解了正态分布的权重分配我们可以继续往下来讲,如果我们在实际对图像做处理的时候其实就是对图像矩阵做处理,图像都是由很多像素排列的矩阵形成的图像,那么权重矩阵该怎么分配呢,很简单就是利用像素点的坐标值通过高斯函数对每个像素点进行运算得出每个像素点的权重值

二维的高斯函数公式

其中x,y代表当前模糊像素点的坐标值,σ代表是模糊半径(指的就是你中心点与周围像素的距离取值),有了这个公式那么算出权重矩阵那就是没那么复杂了,举个栗子,如图:

5*5的卷积核也就是权重矩阵

如果要构建一个模糊半径为2的权重矩阵那么他的矩阵应该是(2*2+1)*(2*2+1),为什么要加1呢是因为作为权重矩阵往往都是奇数矩阵,通常来讲这是为了能有一个中心点,如果不是奇数那么中心点的半径就不是统一的,例如如果是2*2的矩阵那么就无法确定准确的中心点位置,奇数刚好可以解决这个问题;有了这个矩阵我们就可以开始利用高斯函数来进行计算了,将x,y带入函数中,利用java的数学操作可以求出中心点(0,0)及周边的像素点的权重值: sigma(模糊半径)

 
函数在代码中的体现

最后通过每个对矩阵里的每个像素点进行运算求出的矩阵:

权重矩阵

这样我们的权重矩阵也就是卷积核就大功告成了,当然还没有完,假设我们有一个图像矩阵也就是未经过处理的图像矩阵,他们的色值如下图所示:

这个色值值得是图像的RGB色值,那么我们将权重矩阵对准源图像的色值矩阵将权重矩阵和色值矩阵相乘得出个结果全部加起来就可以求出中心的模糊值