野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积

欧,又是坑爹的opencv实验,它又来了额

实验要求:

1.输入三通道RGB直方图

2.直方图均衡化后输出图片及直方图

3.计算鸡蛋的面积(像素数)

首先什么是直方图?

横坐标是灰度,纵坐标是每一个灰度对应出现的频率,现在的彩色图象对应的直方图是R,G,B方向的,灰度不仅只有灰白通道有

直方图均衡化作用:提高图像对比度,拉伸灰度值范围,它有一个算法:

野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积_第1张图片

野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积_第2张图片

 

 

 

 

 代码示例:

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include 

using namespace cv;
using namespace std;

int main(int, char** argv)
{
    Mat src, dst;
    char* yuanlaide = (char*)"yuanlaide";
    char* bianhuahoude = (char*)"bianhuahoude";

    src = imread("C:/echou.jpg");
    if (src.empty()) { return 0; };
    cvtColor(src, src, COLOR_BGR2GRAY);  
    equalizeHist(src, dst);                 // 直方图
    imshow(yuanlaide, src);
    imshow(bianhuahoude, dst);

    waitKey(0);
    return 0;
}

最终显示结果如下:

原图像

野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积_第3张图片

 

 

 变化后的图象:

野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积_第4张图片

 

 

 感觉似乎更臭了

任务2:计算图片直方图

在开始之前我们先看一个Opencv计算直方图的算法:

void cv::calcHist   (   const Mat * images,   int   nimages,
                        const int * channels, InputArray    mask,
                        OutputArray hist,     int   dims,
                        const int * histSize, const float **    ranges,
                        bool uniform = true,  bool  accumulate = false 
)   

现在来讲解一下这个算法,在images输入图象数据,channels对应的rgb通道,https://www.cnblogs.com/phoenixdsg/p/8280362.html这里有一个详细说明这个算法的帖子大家可以看看

输出rgb代码如下:

#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include 

using namespace std;
using namespace cv;

int main( )
{
    Mat src, dst;

    src = imread("C:/echo.jpg");
    if (src.empty()) { return -1; }

    vector bgr_planes;                 // 矩阵向量
    split(src, bgr_planes);                 // 将多通道图像分为多个单通道图像

    int histSize = 256;

    float range[] = { 0,256 };
    const float* histRange = { range };     // 必须加const,否则报错

    bool uniform = true;                    // 直方图是否分布均匀
    bool accumulate = false;                // 如果为true,在开始分配时直方图不会被清除

    Mat b_hist, g_hist, r_hist;

    calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate);
    calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate);
    calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate);

    int hist_w = 512, hist_h = 400;                     // 直方图的横纵范围
    int bin_w = cvRound((double)hist_w / histSize);     // 每个柱状的宽度

    Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));

    normalize(b_hist, b_hist, 9, histImage.rows, NORM_MINMAX, -1, Mat());           // 归一化
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

    for (int i = 1; i < histSize; i++)                                              // 绘制直线
    {
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),    
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))),Scalar(255, 0, 0), 2, 8, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))),Scalar(0, 255, 0), 2, 8, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))),Scalar(0, 0, 255), 2, 8, 0);
    }

    imshow("calcHist Demo", histImage);
    waitKey(0);
    return 0;
}

运行之后输出了恶臭先辈的直方图

野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积_第5张图片

紧接着就是万众瞩目的计算鸡蛋面积

看看这个蛋,表面上只是一个蛋,其实它不是普通的蛋,它是一种叫做“公鸡蛋”的蛋

野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积_第6张图片

 

 什么?公鸡为什么会下蛋呢?公鸡生来就有蛋蛋啊,这不是显而易见的事情吗?

废话不多说,直接开搞!

先考虑对这一张图片进行处理,进行高斯滤波

    Mat dst,dstGray,thres;
    Mat img = imread("C:/egg.jpg");
    GaussianBlur(img, dst, Size(7,7), 0); //高斯变换

紧接着考虑进行灰度变换后二值化,变成只有黑和白的两种颜色,这样可以方便处理

    cvtColor(dst,dstGray, CV_BGR2GRAY); //灰度化
    threshold(dstGray, thres, 80, 255, CV_THRESH_BINARY);

紧接着考虑对二值化后的图片进行平滑处理

    Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3),Point(-1,-1));
    morphologyEx(thres,morp,MORPH_CLOSE,kernel,Point(1,-1),2);

现在开始进行正式的计算了,这里原理是计算白色区块的总像素个数

    vector>contours;
    vectorhireachy;
    findContours(morp,contours,hireachy,CV_RETR_EXTERNAL,CHAIN_APPROX_SIMPLE,Point());
    Mat result = Mat::zeros(img.size(),CV_8UC3);
    for (size_t t = 0; t < contours.size();  t++) {
        Rect rect = boundingRect(contours[t]);
        if (rect.width < img.cols / 2)
        {
            continue;
        }
        if (rect.width > img.cols - 20)
        {
            continue;
        }
        double area = contourArea(contours[t]);
        double len = arcLength(contours[t], true);
        drawContours(result, contours, static_cast<int>(t), Scalar(0, 0, 255), 1, 8, hireachy);
        cout << area << endl;
    }

好了,到这里输出了area的大小,也就是鸡蛋的面积。
谢谢各位!

 

你可能感兴趣的:(野兽先辈带您学Opencv:介绍直方图,直方图均衡化,直方图计算,实战利用直方图计算蛋的面积)