【图像处理】利用C++编写函数,绘制灰度图像直方图

1. 简介

利用OpenCV读取图像,转换为灰度图像,绘制该灰度图像直方图。点击直方图,控制台输出该灰度级像素个数。

2. 原理

(1) 实现原理较为简单,主要利用了OpenCV读取图像,并转换为灰度图像;

    srcImg = imread(" ......");    // “....” 代表图像地址
    if (srcImg.empty()) {
        return -1;
    }
    imshow(WINDOW_SRCIMG, srcImg);
    Mat grayImg;
    cvtColor(srcImg, grayImg, CV_BGR2GRAY);
    imshow(WINDOW_GRAYIMG, grayImg);

(2) 利用Mat类新建一个固定分辨率的画布,统计处于每一灰度级像素个数,在该画布上绘制灰度直方图。

    int nRows = 700,nCols=600;
    Mat g_dstImg(nRows,nCols, CV_8UC1, Scalar::all(0)); // 新建画布

同时避免画布中该灰度级太高而超出画布范围,在本程序中采用了等比例缩小的方法。

    int MaxCount = arrayMax(grayLevel,256);//寻找在处于某一灰度级中个数最多的像素个数
    yscaleRate =  double(nRows)/MaxCount ;//y缩放比例
    double xscaleRate = nCols / 256;//x缩放比例

3. 实施细节

// 灰度直方图.cpp : 定义控制台应用程序的入口点。
// Topic: 绘制灰度图的直方图;  转载请注明出处:Chen_HW (https://www.cnblogs.com/chen-hw/p/11668119.html)// Env: VS2015 + Debug x64 + OpenCV3.4.1
// Date:2018.11.22  by Chen_HW
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#define WINDOW_SRCIMG "【源图】"
#define WINDOW_GRAYIMG "【灰度图】"
#define WINDOW_HIST "【直方图】"
using namespace std;
using namespace cv;
int arrayMax(int g_arr[], int num);
Mat drawHist(Mat &g_srcImg);
void MouseHandle(int event, int x, int y, int flags, void *param);
Point clickPoint,displayPoint;
bool downFlag = false;
Mat srcImg;
double yscaleRate = 0;

int main()
{
    system("color 3f");
    srcImg = imread(" ......");    // “....” 代表图像地址
    if (srcImg.empty()) {
        return -1;
    }
    imshow(WINDOW_SRCIMG, srcImg);
    Mat grayImg;
    cvtColor(srcImg, grayImg, CV_BGR2GRAY);
    imshow(WINDOW_GRAYIMG, grayImg);
    Mat histImg = drawHist(grayImg);
    imshow(WINDOW_HIST, histImg);
    setMouseCallback(WINDOW_HIST, MouseHandle, (void *)&histImg);//(void *)&srcImg传递给void *param
    waitKey();
    return 0;
}
Mat drawHist(Mat &g_srcImg) {
    int nRows = 700,nCols=600;
    Mat g_dstImg(nRows,nCols, CV_8UC1, Scalar::all(0)); // 新建画布
    int grayLevel[256] = {0};
    for (int i = 0; i < g_srcImg.rows; ++i) {
        for (int j = 0; j < g_srcImg.cols; ++j) {
            grayLevel[(int)g_srcImg.at<uchar>(i, j)]++;
        }
    }
    int MaxCount = arrayMax(grayLevel,256);//寻找在处于某一灰度级中个数最多的像素个数
    yscaleRate =  double(nRows)/MaxCount ;//y缩放比例
    double xscaleRate = nCols / 256;//x缩放比例
    int yAxis[256], xAxis[257];
    for (int m = 0; m < 256 ; m++) {
        yAxis[m] = int(grayLevel[m]*yscaleRate);
    }
    //绘制直方图
    for (int n = 0; n < 256; n++) {
        if (n == 255) {
            xAxis[n + 1] = xAxis[n];
        }
        rectangle(g_dstImg, Point(xAxis[n], yAxis[n]), Point( xAxis[n+1], 0), Scalar(255), -1);
                                                                           //-1表示填充矩形框;正值表示不填充矩形框,更方便观察灰度级像素个数的分布;
                                                                          //但因为后面需要用到填充的情况,故设置成填充状态

    }

    return g_dstImg;
}
//num:数组元素个数;g_max:返回最大值
int arrayMax(int g_arr[],int num) {
    int g_max = 0;
    int i = 0;
    while (i < num) {
        if ( g_arr[i]>= g_max) {
            g_max = g_arr[i];
            i++;
        }
        else {
            i++;
        }
    }

    return g_max;
}
//event 鼠标事件(如按下鼠标左键、左键抬起、鼠标移动等) x、y 鼠标坐标
void MouseHandle(int event, int x, int y, int flags, void *param) {
    Mat &g_srcImg = *(Mat *)(param);
    Mat g_tempImg = g_srcImg.clone();
    int nCount=0;//该列白色像素点个数
    int nLevelCount = 0;
    char text[20];//存储文本信息
    float g_rate;//该列像素点占总像素点个数的比例
    imshow(WINDOW_HIST, g_srcImg);
    switch (event) {
    case EVENT_LBUTTONDOWN:
        clickPoint.x = x;
        clickPoint.y = y;
        downFlag = true;
        break;
    default:
        break;
    }
    if (downFlag) {
        //displayPoint.x = clickPoint.x;
        for (int i = 0; i < g_srcImg.rows; ++i) {
            if (int(g_srcImg.at<uchar>(i, x)) == 255) {
                ++nCount;
            }
        }
        nLevelCount = (nCount / yscaleRate);
        g_rate = float(nCount/ yscaleRate) / (srcImg.rows*srcImg.cols);//此处计算的比例不是精确的
        cout << "该灰度级像素点个数: " << nLevelCount << ";占总像素个数的比例: "<<g_rate << endl;
        sprintf_s(text, "Rate:%f",g_rate );//该灰度级像素个数占总个数的比例;
        putText(g_tempImg, text, clickPoint,FONT_HERSHEY_PLAIN,1,Scalar(255,0,255));
        imshow(WINDOW_HIST, g_tempImg);
        downFlag = false;
    }
}

4. 结果

  结果如下图所示,点击右侧每一级灰度直方图,在控制台中会输出该灰度级像素个数,并显示占总像素比例。

原文地址:https://www.cnblogs.com/chen-hw/p/11668119.html

时间: 2024-11-08 22:39:46

【图像处理】利用C++编写函数,绘制灰度图像直方图的相关文章

【数字图像处理】四.MFC对话框绘制灰度直方图

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行回忆讲解,主要通过MFC单文档视图实现点击弹出对话框绘制BMP图片的灰度直方图,再获取平均灰度.中指灰度和标准差等值.文章比较详细基础,希望该篇文章对你有所帮助~ [数字图像处理]一.MFC详解显示BMP格式图片 [数字图像处理]二.MFC单文档分割窗口显示图片 [数字图像处理]三.MFC实现图像灰度.采样和量化功能详解 免费资源下载地址: http://download.csdn.ne

利用OpenCV的calcHist绘制灰度直方图、H-S直方图、BGR直方图和自定义直方图的源码及说明

要绘制直方图,最重要的三个函数是calcHist.line.和rectangle,下面分别进行介绍! calcHist函数: calcHist函数的原型如下: void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=t

使用matplotlib中的bar函数绘制柱状图

使用柱状图显示三日电影的票房信息 要显示的数据为2018年12月7日-9日四场电影的票房信息 四场电影分别为:无名之辈,狗十三,毒液:知名守卫者,憨豆特工3 2018年12月7日四场电影票房分别为:[991.94, 375.64, 200.48, 73.27] 2018年12月8日四场电影票房分别为:[1908.22, 547.61, 466.23, 193.8] 2018年12月9日四场电影票房分别为:[1532.87, 525.63, 332.35, 170.57] 本次绘图思路: 1.x轴

SA:T1法利用Matlab编写主函数实现对一元函数优化求解——Jason niu

%SA:T1法利用Matlab编写主函数实现对一元函数优化求解--Jason niu x = 1:0.01:2; y = sin(10*pi*x) ./ x; figure plot(x,y,'linewidth',1.5) ylim([-1.5, 1.5]) xlabel('x') ylabel('y') title('SA:T1法利用Matlab编写主函数实现对一元函数y = sin(10*pi*x) / x优化求解-Jason niu') hold on [maxVal,maxIndex]

利用Flex组件birdeye绘制拓扑关系图

原文:利用Flex组件birdeye绘制拓扑关系图 birdeye绘制拓扑关系图 1.flex简单介绍 Flex 是一个高效.免费的开源框架,可用于构建具有表现力的 Web应用程序,这些应用程序利用Adobe Flash Player和Adobe AIR, 可以实现跨浏览器.桌面和操作系统.虽然只能使用 Flex 框架构建 Flex应用程序,但Adobe Flash Builder™(之前称为 Adobe Flex Builder™)软件可以通过智能编码.交互式遍历调试以及可视设计用户界面布局等

看我如何利用Shell编写vsftpd管理软件

今天弄服务器的时候无意间用到此脚本,觉得当时写的虽然不咋样,但还是有点借鉴意义,就拿出来给大家看看.希望大家喜欢 先看看演示视频 看我如何利用Shell编写vsftpd管理软件 高清版下载: 百度云下载 OK然后我们来看看脚本的实现过程,时间有点久了当时的想法可能现在有点想不起来了,解释的不对的地方望见谅 脚本分为7个部分,这里我只做简单的解释 第一部分 脚本开始就利用awk提取日志中的用户名字段保存到tmp目录下的ftplog-userlist.txt文件中,方便后面查询 然后开始信息的展示,

利用MFC编写计算器

端午节这两天没什么事,就用MFC写了一个简单的计算器,界面做的也比较简单,如下图1,可以进行简单的加.减.乘和除功能,小数点显示这块做的不是很好,比如输入1.2,不会一个个的显示,而是先显示"1",后同时显示".2",还有就是遇到0.00时,显示的也不够人性化,哎,就这样吧... 图1 1.建立工程:New -> Projects,选择Win32 MFC AppWizard(exe),并输入工程(counter)名字及设置好路径,点击OK,选择"Di

DirectX学习笔记(四):利用D3DX网格数据结构绘制可旋转茶壶

前言: 在上篇文章(DirectX学习笔记三)中,我详细的说明了如何利用线框模式绘制可旋转的正方体.链接:点击打开链接.但是应该看到的是,如果我们通过创建三角形单元来创建3D物体是十分繁琐的事情.幸运的是,在D3DX库中提供了一些用于生成简单3D物体的网格数据方法. 如:利用网格数据创建一个茶壶: 1. 我们需要使用ID3DXMesh网格数据结构接口来创建我们的茶壶网格数据,这时我们需要使用此函数: HRESULT D3DXCreateTeapot(LPDIRECT3DDEVICE9 pDevi

品味性能之道&lt;九&gt;:利用Loadrunner编写socket性能测试脚本简述

一.概述 Loadrunner拥有极为丰富的工具箱,供予我们制造出各种奇妙魔法的能力.其中就有此次要讨论的socket套接字操作. 二.socket概述 socket是操作系统中I/O系统的网络延伸部分,它扩展了操作系统的基本I/O到网络通信,使进程和机器之间的通信成为可能.如果想完全地理解socket在Loadrunner中如何工作的,熟悉一些关于它的历史会很有帮助. 当前常用的socket,最早起源于BSD UNIX类的操作系统.在UNIX系统上,比如BSD,把对网络的支持加入操作系统,以一