MENU

经典 Fork 炸弹解析

原文出处:saymagic

Jaromil 在 2002 年设计了最为精简的一个Linux Fork炸弹,整个代码只有13个字符,在 shell 中运行后几秒后系统就会宕机:

:(){:|:&};:
这样看起来不是很好理解,我们可以更改下格式:
:()
{
    :|:&
};
:

阅读全文

五月读书推荐《了不起的盖茨比》

“暴发户”永远也进不了“世族”的特权阶层。

这些特权阶层不会允许一个暴发户与自己平起平坐,以汤姆为代表的上流特权阶层心狠手辣,表面上再怎么温文尔雅,背后也是麻木不仁。盖茨比宴会上邀请的各界名流,在享受着免费的欢乐同时,传播着关于盖茨比的流言蜚语。

盖茨比的美国梦注定会烟消云散,当财富遇到特权,要么破财,要么损命。当爱情在这之间,算个屁!

重置 MySQL 的 root 密码

在Linux下重置Mysql的root密码非常容易,基本的思路是,以安全模式启动mysql,这样不需要密码可以直接以root身份登录,然后重设密码。

测试环境为 CentOS 7, MySQL 5.6

阅读全文

C语言关键字static

<h4>1.作用于变量</h4>
用static声明局部变量

用static声明局部变量时,则改变变量的存储方式(生命期),使变量成为静态的局部变量,即编译时就为变量分配内存,直到程序退出才释放存储单元。这样,使得该局部变量有记忆功能,可以记忆上次的数据,不过由于仍是局部变量,因而只能在代码块内部使用(作用域不变)。


阅读全文

Linux系统错误代码

在Linux下,系统请求失败后会返回错误代码。/usr/include/asm-generic/errno.h这个文件解释了错误代码的含义。

文件版本:2017/04/22 on CentOS 6.5

#ifndef _ASM_GENERIC_ERRNO_H
#define _ASM_GENERIC_ERRNO_H

#include <asm-generic/errno-base.h>

#define	EDEADLK		35	/* Resource deadlock would occur */
#define	ENAMETOOLONG	36	/* File name too long */
#define	ENOLCK		37	/* No record locks available */
#define	ENOSYS		38	/* Function not implemented */
#define	ENOTEMPTY	39	/* Directory not empty */
#define	ELOOP		40	/* Too many symbolic links encountered */
#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
#define	ENOMSG		42	/* No message of desired type */
#define	EIDRM		43	/* Identifier removed */
#define	ECHRNG		44	/* Channel number out of range */
#define	EL2NSYNC	45	/* Level 2 not synchronized */
#define	EL3HLT		46	/* Level 3 halted */
#define	EL3RST		47	/* Level 3 reset */
#define	ELNRNG		48	/* Link number out of range */
#define	EUNATCH		49	/* Protocol driver not attached */
#define	ENOCSI		50	/* No CSI structure available */
#define	EL2HLT		51	/* Level 2 halted */
#define	EBADE		52	/* Invalid exchange */
#define	EBADR		53	/* Invalid request descriptor */
#define	EXFULL		54	/* Exchange full */
#define	ENOANO		55	/* No anode */
#define	EBADRQC		56	/* Invalid request code */
#define	EBADSLT		57	/* Invalid slot */

#define	EDEADLOCK	EDEADLK

#define	EBFONT		59	/* Bad font file format */
#define	ENOSTR		60	/* Device not a stream */
#define	ENODATA		61	/* No data available */
#define	ETIME		62	/* Timer expired */
#define	ENOSR		63	/* Out of streams resources */
#define	ENONET		64	/* Machine is not on the network */
#define	ENOPKG		65	/* Package not installed */
#define	EREMOTE		66	/* Object is remote */
#define	ENOLINK		67	/* Link has been severed */
#define	EADV		68	/* Advertise error */
#define	ESRMNT		69	/* Srmount error */
#define	ECOMM		70	/* Communication error on send */
#define	EPROTO		71	/* Protocol error */
#define	EMULTIHOP	72	/* Multihop attempted */
#define	EDOTDOT		73	/* RFS specific error */
#define	EBADMSG		74	/* Not a data message */
#define	EOVERFLOW	75	/* Value too large for defined data type */
#define	ENOTUNIQ	76	/* Name not unique on network */
#define	EBADFD		77	/* File descriptor in bad state */
#define	EREMCHG		78	/* Remote address changed */
#define	ELIBACC		79	/* Can not access a needed shared library */
#define	ELIBBAD		80	/* Accessing a corrupted shared library */
#define	ELIBSCN		81	/* .lib section in a.out corrupted */
#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
#define	EILSEQ		84	/* Illegal byte sequence */
#define	ERESTART	85	/* Interrupted system call should be restarted */
#define	ESTRPIPE	86	/* Streams pipe error */
#define	EUSERS		87	/* Too many users */
#define	ENOTSOCK	88	/* Socket operation on non-socket */
#define	EDESTADDRREQ	89	/* Destination address required */
#define	EMSGSIZE	90	/* Message too long */
#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
#define	ENOPROTOOPT	92	/* Protocol not available */
#define	EPROTONOSUPPORT	93	/* Protocol not supported */
#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
#define	EPFNOSUPPORT	96	/* Protocol family not supported */
#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
#define	EADDRINUSE	98	/* Address already in use */
#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
#define	ENETDOWN	100	/* Network is down */
#define	ENETUNREACH	101	/* Network is unreachable */
#define	ENETRESET	102	/* Network dropped connection because of reset */
#define	ECONNABORTED	103	/* Software caused connection abort */
#define	ECONNRESET	104	/* Connection reset by peer */
#define	ENOBUFS		105	/* No buffer space available */
#define	EISCONN		106	/* Transport endpoint is already connected */
#define	ENOTCONN	107	/* Transport endpoint is not connected */
#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
#define	ETIMEDOUT	110	/* Connection timed out */
#define	ECONNREFUSED	111	/* Connection refused */
#define	EHOSTDOWN	112	/* Host is down */
#define	EHOSTUNREACH	113	/* No route to host */
#define	EALREADY	114	/* Operation already in progress */
#define	EINPROGRESS	115	/* Operation now in progress */
#define	ESTALE		116	/* Stale NFS file handle */
#define	EUCLEAN		117	/* Structure needs cleaning */
#define	ENOTNAM		118	/* Not a XENIX named type file */
#define	ENAVAIL		119	/* No XENIX semaphores available */
#define	EISNAM		120	/* Is a named type file */
#define	EREMOTEIO	121	/* Remote I/O error */
#define	EDQUOT		122	/* Quota exceeded */

#define	ENOMEDIUM	123	/* No medium found */
#define	EMEDIUMTYPE	124	/* Wrong medium type */
#define	ECANCELED	125	/* Operation Canceled */
#define	ENOKEY		126	/* Required key not available */
#define	EKEYEXPIRED	127	/* Key has expired */
#define	EKEYREVOKED	128	/* Key has been revoked */
#define	EKEYREJECTED	129	/* Key was rejected by service */

/* for robust mutexes */
#define	EOWNERDEAD	130	/* Owner died */
#define	ENOTRECOVERABLE	131	/* State not recoverable */

#define ERFKILL		132	/* Operation not possible due to RF-kill */

#define EHWPOISON	133	/* Memory page has hardware error */

#endif

 

基于Qt的图像处理算法和实现——索贝尔边缘检测

索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量

Sobel卷积因子为:

$$\begin{matrix}
\left [ \begin{matrix}
-1 & 0 & +1\\
-2 & 0 & +2 \\
-2 & 0 & +1
\end{matrix} \right ]& \left [ \begin{matrix}
+1 & +2 & +1\\
0 & 0 & 0 \\
-1 & -2 & -1
\end{matrix}\right ]\\
Gx & Gy
\end{matrix}$$

该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,GxGy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:

$$\begin{align*}
G_{x} &= \left [ \begin{matrix}
-1 & 0 & +1\\
-2 & 0 & +2\\
-1 & 0 & +1
\end{matrix} \right ]*A
\\
G_{y} &= \left [ \begin{matrix}
+1 & +2 & +1\\
0 & 0 & 0\\
-1 & -2 & -1
\end{matrix} \right ]*A
\end{align*}$$

图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:

$$G = \sqrt{ G_{x}^{2} + G_{y}^{2} }$$

通常,为了提高效率 使用不开平方的近似值:

$$\left | G \right | = \left | G_{x} \right | + \left | G_{y} \right |$$

如果梯度G大于某一阀值 则认为该点(x,y)为边缘点。

然后可用以下公式计算梯度方向:

$$\theta = arctan(\frac{G_{y}}{G_{x}})$$

Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

算法实现:

QImage Tools::SobelEdge(const QImage &origin)
{
    double *Gx = new double[9];
    double *Gy = new double[9];

    /* Sobel */
    Gx[0] = 1.0; Gx[1] = 0.0; Gx[2] = -1.0;
    Gx[3] = 2.0; Gx[4] = 0.0; Gx[5] = -2.0;
    Gx[6] = 1.0; Gx[7] = 0.0; Gx[8] = -1.0;

    Gy[0] = -1.0; Gy[1] = -2.0; Gy[2] = - 1.0;
    Gy[3] = 0.0; Gy[4] = 0.0; Gy[5] = 0.0;
    Gy[6] = 1.0; Gy[7] = 2.0; Gy[8] = 1.0;

    QRgb pixel;
    QImage grayImage = GreyScale(origin);
    int height = grayImage.height();
    int width = grayImage.width();
    QImage newImage = QImage(width, height,QImage::Format_RGB888);

    float sobel_norm[width*height];
    float max = 0.0;
    QColor my_color;

    for (int x=0; x<width; x++)
    {
        for( int y=0; y<height; y++)
        {
            double value_gx = 0.0;
            double value_gy = 0.0;

            for (int k=0; k<3;k++)
            {
                for(int p=0; p<3; p++)
                {
                    pixel=grayImage.pixel(x+1+1-k,y+1+1-p);
                    value_gx += Gx[p*3+k] * qRed(pixel);
                    value_gy += Gy[p*3+k] * qRed(pixel);
                }
//                sobel_norm[x+y*width] = sqrt(value_gx*value_gx + value_gy*value_gy)/1.0;
                sobel_norm[x+y*width] = abs(value_gx) + abs(value_gy);

                max=sobel_norm[x+y*width]>max ? sobel_norm[x+y*width]:max;
            }
        }
    }

    for(int i=0;i<width;i++){
        for(int j=0;j<height;j++){
            my_color.setHsv( 0 ,0, 255-int(255.0*sobel_norm[i + j * width]/max));
            newImage.setPixel(i,j,my_color.rgb());
        }
    }
    return newImage;
}

处理效果:

[caption id="attachment_1689" align="aligncenter" width="225"] 原图[/caption]

[caption id="attachment_1690" align="aligncenter" width="225"] 处理后[/caption]

 

 

基于Qt的图像处理算法和实现——拉普拉斯锐化

锐化的目的是为了突出图像的边缘和细节,图像的二阶导数反映了图像的细节。

当邻域中心像素灰度低于它所在的领域内其它像素的平均灰度时,此中心像素的灰度应被进一步降低,当邻域中心像素灰度高于它所在的邻域内其它像素的平均灰度时,此中心像素的灰度应被进一步提高,以此实现图像的锐化处理。

操作原理

  1. 基于一阶微分的图像增强原理

对于二元函数的一阶偏微分微分表示如下:

$$\frac{\partial f}{\partial x} = f(x,y) - f(x-1, y) $$

$$\frac{\partial f}{\partial y} = f(x,y) - f(x, y-1)$$

定义二元函数的微分为:

$$\begin{align*}
\bigtriangledown f &= \frac{\partial f}{\partial x} + \frac{\partial f}{\partial y} \\
&= f(x,y)-f(x-1,y)+f(x,y)-f(x,y-1)\\
&=2f(x,y)-f(x-1,y)-f(x,y-1)
\end{align*}$$

这就描述了图像中一个像素点(x,y)的一阶微分变化。简单的总结为一个算子的话就是一个2*2的矩阵如下:

$$\begin{matrix}
-1 & 2 \\
0 & -1
\end{matrix}$$

将用这个算子处理后的值与(x,y)处原有的值相加,就可以将使这种变化更明显,也就是放大这种变化,从而达到图像锐化的目的。

2. 基于二阶微分的图像增强处理

类似上面的推导过程我们得到二阶微分:

$$\bigtriangledown ^2 f=f(x+1,y)+f(x-1,y)+f(x,y+1)+f(x,y-1)-4f(x,y)$$

从而得到拉普拉斯算子:

$$\begin{matrix}
0 & -1 & 0\\
-1 & 4 & -1\\
0 & -1 & 0
\end{matrix}$$

用这个算子对图像的每个像素进行处理得到的是图像的变化程度,应该将这种变化叠加到原图像:

$$g(x,y)=
\left\{\begin{matrix}
f(x,y)-\bigtriangledown ^{2} f(x,y), & \text{ A }<0 \\
f(x,y)+\bigtriangledown ^{2} f(x,y), & \text{ A }>0
\end{matrix}\right.$$

上式中A为拉普拉斯掩模中心系数,如上面的拉普拉斯算子中该系数为4.

注:每个像素R、G、B应该分别做如上处理。

算法实现(Qt/C++):

QImage LaplaceSharpen(const QImage &origin)
{
    int width = origin.width();
    int height = origin.height();
    QImage newImage = QImage(width, height,QImage::Format_RGB888);
    int window[3][3] = {0,-1,0,-1,4,-1,0,-1,0};

    for (int x=1; x<width; x++)
    {
        for(int y=1; y<height; y++)
        {
            int sumR = 0;
            int sumG = 0;
            int sumB = 0;

            //对每一个像素使用模板
            for(int m=x-1; m<= x+1; m++)
                for(int n=y-1; n<=y+1; n++)
                {
                    if(m>=0 && m<width && n<height)
                    {
                        sumR += QColor(origin.pixel(m,n)).red()*window[n-y+1][m-x+1];
                        sumG += QColor(origin.pixel(m,n)).green()*window[n-y+1][m-x+1];
                        sumB += QColor(origin.pixel(m,n)).blue()*window[n-y+1][m-x+1];
                    }
                }


            int old_r = QColor(origin.pixel(x,y)).red();
            sumR += old_r;
            sumR = qBound(0, sumR, 255);

            int old_g = QColor(origin.pixel(x,y)).green();
            sumG += old_g;
            sumG = qBound(0, sumG, 255);

            int old_b = QColor(origin.pixel(x,y)).blue();
            sumB += old_b;
            sumB = qBound(0, sumB, 255);


            newImage.setPixel(x,y, qRgb(sumR, sumG, sumB));
        }
    }
    return newImage;
}

效果截图:

[caption id="attachment_1685" align="aligncenter" width="650"] 原图[/caption]

[caption id="attachment_1686" align="aligncenter" width="650"] 处理后[/caption]

 

机器学习环境搭建:openSUSE 42.2+TensorFlow

最近在做图像识别需要用到Tensorflow,这里记录下安装的过程。因为安装到现在已经比较久远,下面有些地方可能有些许丢失,如果出现问题注意仔细查看报错信息。

编译安装会比下载通用的二进制包具有更好的性能。因为自己的笔记本电脑上没有nVidia的显卡,所以没有启动CUDA支持,下面的安装都是针对Python3.(我还是个小孩子,没赶上Python2)

1.安装前的准备

最好提前准备下以下几个软件包

python-devel

python3-devel

python-numpy

python-wheel

其中 python-numpy 和 python-wheel 可以直接在 pip 中安装 numpy 和 wheel

除此还需要Java的环境,具体配置过程请参考之前的这篇文章《openSUSE配置 Oracle JDK 开发环境

2.安装Google构建工具Bazel

Bazel是Google官方开源的一个构建工具,用来配合Google的软件开发模式。

从Github上下载 Bazel 最新的 Linux Release 版本:

[url href=“https://github.com/bazelbuild/bazel/releases/download/0.4.5/bazel-0.4.5-installer-linux-x86_64.sh”]下载 Bazel Linux Release 0.4.5[/url]

下载完成后执行:

chmod +x bazel-0.4.5-installer-linux-x86_64.sh
./bazel-0.4.5-installer-linux-x86_64.sh --user

安装完成后会有类似这样的提示:

Bazel is now installed!

Make sure you have "/home/jjt/bin" in your path. You can also activate bash
completion by adding the following line to your ~/.bashrc:
source /home/jjt/.bazel/bin/bazel-complete.bash

See http://bazel.io/docs/getting-started.html to start a new project!

然后在 ~/.bashrc中追加:

source /home/jjt/.bazel/bin/bazel-complete.bash
export PATH=$PATH:/home/jjt/.bazel/bin

之后执行一下:

source ~/.bashrc

3.编译安装Tensorflow

首先从github上克隆TensorFlow最新的代码:

git clone https://github.com/tensorflow/tensorflow

代码下载完毕之后,进入tensorflow主目录,执行:

./configure

这里会有很多提示,除了几个选择Yes或No的选项外,其他直接回车就好。这里我没有启用CUDA、Hadoop File System等特性。

执行一下TensorFlow官方文档里的例子,看看能不能成功,成功的话会有一堆数据输出。

bazel-bin/tensorflow/cc/tutorials_example_trainer
000003/000006 lambda = 1.841570 x = [0.669396 0.742906] y = [3.493999 -0.669396]
000006/000007 lambda = 1.841570 x = [0.669396 0.742906] y = [3.493999 -0.669396]
000009/000006 lambda = 1.841570 x = [0.669396 0.742906] y = [3.493999 -0.669396]
000009/000004 lambda = 1.841570 x = [0.669396 0.742906] y = [3.493999 -0.669396]
000000/000005 lambda = 1.841570 x = [0.669396 0.742906] y = [3.493999 -0.669396]
000000/000004 lambda = 1.841570 x = [0.669396 0.742906] y = [3.493999 -0.669396]

输出类似上面这样。

这时我们还不能直接在Python中import,继续下面的操作:

bazel build -c opt //tensorflow/tools/pip_package:build_pip_package
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
sudo pip3 install /tmp/tensorflow_pkg/tensorflow-1.1.0rc0-cp34-cp34m-linux_x86_64.whl

至此大功告成,可以在Python3中愉快地使用了!

基于Qt的图像处理算法和实现——线性灰度变换

灰度的线性变换使用的变换函数是一个一维的线性函数:y = ax + b

x为原灰度值,y即得到的新灰度。

当a>1时,输出图像的对比度将增大;

当a<1时,输出图像的对比度将减小;

当a=1时且b≠0时,变换将使灰度值上移或下移,其效果是使整个图像变亮或变暗(我们在《基于Qt的图像处理算法和实现——灰度图像、冷暖色调、亮度》这篇文章中改变图像亮度时就是直接对各颜色分量的值进行加减操作);

当a<0时,暗区域将变亮,亮区域将变暗。

特殊情况:a=01,d=255时,输出图像的灰度相反。

示例代码

下面的代码针对所有类型的图像文件,不仅仅是位图,所以第一步操作是根据RGB值计算灰度值。对于彩色转灰度,有一个很著名的心理学公式:

$$Gray = R*0.299 + G*0.587 + B*0.114$$

至于用这个公式而不是直接取平均值,是因为人眼对RGB颜色的感知程度并不相同,所以在转换的时候应该分别为RGB设置不同的权重。至于其背后的详细说明及物理上的原理,请移步知乎的这个帖子:

传送门:知乎 RGB 转为灰度值的心理学公式 Gray = 0.30 * R + 0.59 * G + 0.11 * B 是怎么来的?

考虑到一幅图像的每个像素都需要使用上面的公式,计算量比较大,我们这里采用了:

$$ Gray = (R*299 + G*587 + B*114 + 500) / 1000$$

这个公式,注意后面那个除法是整数除法,所以需要加上500来实现四舍五入。

/*****************************************************************************
 *                           线性灰度变换 y = ax + b
 * **************************************************************************/
QImage Tools::LinearLevelTransformation(const QImage &origin, double _a, double _b)
{
    QImage *newImage = new QImage(origin.width(), origin.height(),
                                   QImage::Format_ARGB32);
    QColor oldColor;
    int grayLevel = 0;

    for (int x=0; x<newImage->width(); x++) {
        for (int y=0; y<newImage->height(); y++) {
            oldColor = QColor(origin.pixel(x,y));
            grayLevel = (oldColor.red()*299+oldColor.green()*587+oldColor.blue()*114+500)/1000;
            int _y = _a*grayLevel + _b;
            // Make sure that the new values are between 0 and 255
            _y = qBound(0, _y, 255);

            newImage->setPixel(x,y,qRgb(_y,_y,_y));
        }
    }
//    qDebug()<<"a:"<<_a<<"\tb:"<<_b;

    return *newImage;
}

注意,变换之后得到的灰度应该控制在 0~255之间。

效果截图

[caption id="attachment_1672" align="aligncenter" width="985"] 线性灰度变换[/caption]

上图中是 a =1.2, b=0时的效果

基于Qt的图像处理算法和实现——绘制图像直方图

关于图像直方图的介绍可以看我以前的一篇文章《图像处理中的直方图均衡化

这篇文章介绍了使用Qt绘制图像的直方图,包括灰度直方图和各颜色分量的直方图。

具体算法实现

#ifndef HISTOGRAM_H
#define HISTOGRAM_H

#include <QWidget>
#include <QLabel>
#include <QPainter>
#include <QDebug>

class Histogram : public QLabel
{
public:
    Histogram(QWidget* parent = 0);
    Histogram(QWidget*, Histogram*);

    void computeHstgrm(QImage img);
    void paintEvent(QPaintEvent *e);
    void drawBwHstgrm(int xBase, int yBase, int height);
    void drawRedHstgrm(int xBase, int yBase, int height);
    void drawGreenHstgrm(int xBase, int yBase, int height);
    void drawBlueHstgrm(int xBase, int yBase, int height);
    int getBwHstgrm(int index);
    int getRedHstgrm(int index);
    int getGreenHstgrm(int index);
    int getBlueHstgrm(int index);

private:
    // index 0 to 255 => count of image's pixels for this value
    // index 256 => maximum value
    // index 257 => total value of the dark component
    // index 258 => total value of the light component
    int bwHstgrm[259];

    // index 0 to 255 => count of image's pixels for this value
    // index 256 => maximum value
    // index 257 => total value of the component
    int redHstgrm[258];
    int greenHstgrm[258];
    int blueHstgrm[258];
};

#endif // HISTOGRAM_H
#include "histogram.h"

#include <sstream>
#include <iostream>


Histogram::Histogram(QWidget * parent) : QLabel(parent)
{
    for(int i = 0;i<256;i++)
    {
        bwHstgrm[i] = 0;
        redHstgrm[i] = 0;
        greenHstgrm[i] = 0;
        blueHstgrm[i] = 0;
    }

    bwHstgrm[256] = -1;
    redHstgrm[256] = -1;
    greenHstgrm[256] = -1;
    blueHstgrm[256] = -1;

    redHstgrm[257] = 0;
    greenHstgrm[257] = 0;
    blueHstgrm[257] = 0;

    bwHstgrm[257] = 0;
    bwHstgrm[258] = 0;
}



Histogram::Histogram(QWidget * parent, Histogram * hstgrm) : QLabel(parent)
{
    for(int i = 0;i<258;i++)
    {
        bwHstgrm[i] = hstgrm->bwHstgrm[i];
        redHstgrm[i] = hstgrm->redHstgrm[i];
        greenHstgrm[i] = hstgrm->greenHstgrm[i];
        blueHstgrm[i] = hstgrm->blueHstgrm[i];
    }

    bwHstgrm[258] = hstgrm->bwHstgrm[258];
}



void Histogram::computeHstgrm(QImage img)
{
    if (!img.isNull())
    {
        for(int i = 0;i<img.height();i++)
        {
            for(int j = 0;j<img.width();j++)
            {
                int bwValue = qGray(img.pixel(j, i));

                int redValue = qRed(img.pixel(j, i));
                int greenValue = qGreen(img.pixel(j, i));
                int blueValue = qBlue(img.pixel(j, i));

                bwHstgrm[bwValue]++;
                redHstgrm[redValue]++;
                greenHstgrm[greenValue]++;
                blueHstgrm[blueValue]++;
            }
        }

        for(int i = 0;i<256;i++)
        {
            // maximum values
            if (bwHstgrm[256] < bwHstgrm[i])
                bwHstgrm[256] = bwHstgrm[i];

            if (redHstgrm[256] < redHstgrm[i])
                redHstgrm[256] = redHstgrm[i];

            if (greenHstgrm[256] < greenHstgrm[i])
                greenHstgrm[256] = greenHstgrm[i];

            if (blueHstgrm[256] < blueHstgrm[i])
                blueHstgrm[256] = blueHstgrm[i];

            // values of colour components
            redHstgrm[257] += i*redHstgrm[i];
            greenHstgrm[257] += i*greenHstgrm[i];
            blueHstgrm[257] += i*blueHstgrm[i];

            // values of dark and light component
            if (i <= 127)
                bwHstgrm[257] += (127-i)*bwHstgrm[i];
            else
                bwHstgrm[258] += (i-127)*bwHstgrm[i];
        }
    }
}



void Histogram::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);

    int step = 100;              // distance between histograms
    int height = 255+10;        // histograms height
    int xBase = 99;             // x coordinate of the first histogram origin
    int yBase = 30+height+1;    // y coordinate of the first histogram origin

    QPainter painter(this);
    painter.setPen(Qt::black);


    // 显示在第一行
    // bw hstgrm
    if (bwHstgrm[256] != -1)
        drawBwHstgrm(xBase, yBase, height);
    else
        painter.drawText(xBase, yBase-height/2+5, tr("Can't load the gray levels histogram."));

    // red hstgrm
    if (redHstgrm[256] != -1)
        drawRedHstgrm(xBase+step+height, yBase, height);
    else
        painter.drawText(xBase+step+height+1-height/2+5, yBase, tr("Can't load the red component histogram."));


    // 显示在第二行
    // green hstgrm
    if (greenHstgrm[256] != -1)
        drawGreenHstgrm(xBase, yBase+step+height+1, height);
    else
        painter.drawText(xBase, yBase+(step+height+1), tr("Can't load the green component histogram."));
    // blue hstgrm
    if (blueHstgrm[256] != -1)
        drawBlueHstgrm(xBase+step+height, yBase+step+height+1, height);
    else
        painter.drawText(xBase+step+height, yBase+step+height+1, tr("Can't load the blue component histogram."));

}



void Histogram::drawBwHstgrm(int xBase, int yBase, int height)
{
    QPainter painter(this);

    painter.setPen(Qt::darkGray);

    float max = bwHstgrm[256];

    if (max < redHstgrm[256])
        max = redHstgrm[256];

    if (max < greenHstgrm[256])
        max = greenHstgrm[256];

    if (max < blueHstgrm[256])
        max = blueHstgrm[256];

    // drawing the histogram
    for(int i = 0;i<256;i++)
    {
        painter.drawLine(xBase+1+i, yBase, xBase+1+i,
            yBase-(float)(256./max)*(float)bwHstgrm[i]);
    }

    painter.drawText(xBase, yBase+25, tr("black"));
    painter.drawText(xBase+220, yBase+25, tr("white"));

    painter.setPen(Qt::black);

    painter.drawText(xBase+40, yBase-height-10, tr("GRAY LEVELS HISTOGRAM"));

    painter.drawText(xBase+100, yBase+15, tr("Intensity"));
    painter.drawText(xBase-84, yBase-height/2+5, tr("Pixels count"));

    // abscissa
    painter.drawLine(xBase, yBase, xBase+256+1, yBase);
    painter.drawLine(xBase, yBase+1, xBase+256+1, yBase+1);

    // left ordinate
    painter.drawLine(xBase, yBase, xBase, yBase-height);
    painter.drawLine(xBase-1, yBase, xBase-1, yBase-height);

    // right ordinate
    painter.drawLine(xBase+256+1, yBase, xBase+256+1, yBase-height);
    painter.drawLine(xBase+256+2, yBase, xBase+256+2, yBase-height);

    // left ordinate arrow
    painter.drawLine(xBase, yBase-height, xBase+4, yBase-height+7);
    painter.drawLine(xBase-1, yBase-height, xBase-1-4, yBase-height+7);

    // right ordinate arrow
    painter.drawLine(xBase+256+1, yBase-height, xBase+256+1-4, yBase-height+7);
    painter.drawLine(xBase+256+2, yBase-height, xBase+256+2+4, yBase-height+7);
}



void Histogram::drawRedHstgrm(int xBase, int yBase, int height)
{
    QPainter painter(this);

    painter.setPen(Qt::darkRed);

    float max = bwHstgrm[256];

    if (max < redHstgrm[256])
        max = redHstgrm[256];

    if (max < greenHstgrm[256])
        max = greenHstgrm[256];

    if (max < blueHstgrm[256])
        max = blueHstgrm[256];

    // drawing the histogram
    for(int i = 0;i<256;i++)
    {
        painter.drawLine(xBase+1+i, yBase, xBase+1+i,
            yBase-(float)(256./max)*(float)redHstgrm[i]);
    }

    painter.drawText(xBase, yBase+25, tr("dark"));
    painter.drawText(xBase+225, yBase+25, tr("light"));

    painter.setPen(Qt::black);

    painter.drawText(xBase+25, yBase-height-10, tr("RED COMPONENT HISTOGRAM"));

    painter.drawText(xBase+100, yBase+15, tr("Intensity"));
    painter.drawText(xBase-84, yBase-height/2+5, tr("Pixels count"));

    // abscissa
    painter.drawLine(xBase, yBase, xBase+256+1, yBase);
    painter.drawLine(xBase, yBase+1, xBase+256+1, yBase+1);

    // left ordinate
    painter.drawLine(xBase, yBase, xBase, yBase-height);
    painter.drawLine(xBase-1, yBase, xBase-1, yBase-height);

    // right ordinate
    painter.drawLine(xBase+256+1, yBase, xBase+256+1, yBase-height);
    painter.drawLine(xBase+256+2, yBase, xBase+256+2, yBase-height);

    // left ordinate arrow
    painter.drawLine(xBase, yBase-height, xBase+4, yBase-height+7);
    painter.drawLine(xBase-1, yBase-height, xBase-1-4, yBase-height+7);

    // right ordinate arrow
    painter.drawLine(xBase+256+1, yBase-height, xBase+256+1-4, yBase-height+7);
    painter.drawLine(xBase+256+2, yBase-height, xBase+256+2+4, yBase-height+7);
}



void Histogram::drawGreenHstgrm(int xBase, int yBase, int height)
{
    QPainter painter(this);

    painter.setPen(Qt::darkGreen);

    float max = bwHstgrm[256];

    if (max < redHstgrm[256])
        max = redHstgrm[256];

    if (max < greenHstgrm[256])
        max = greenHstgrm[256];

    if (max < blueHstgrm[256])
        max = blueHstgrm[256];

    // drawing the histogram
    for(int i = 0;i<256;i++)
    {
        painter.drawLine(xBase+1+i, yBase, xBase+1+i,
            yBase-(float)(256./max)*(float)greenHstgrm[i]);
    }

    painter.drawText(xBase, yBase+25, tr("dark"));
    painter.drawText(xBase+225, yBase+25, tr("light"));

    painter.setPen(Qt::black);

    painter.drawText(xBase+15, yBase-height-10, tr("GREEN COMPONENT HISTOGRAM"));

    painter.drawText(xBase+100, yBase+15, tr("Intensity"));
    painter.drawText(xBase-84, yBase-height/2+5, tr("Pixels count"));

    // abscissa
    painter.drawLine(xBase, yBase, xBase+256+1, yBase);
    painter.drawLine(xBase, yBase+1, xBase+256+1, yBase+1);

    // left ordinate
    painter.drawLine(xBase, yBase, xBase, yBase-height);
    painter.drawLine(xBase-1, yBase, xBase-1, yBase-height);

    // right ordinate
    painter.drawLine(xBase+256+1, yBase, xBase+256+1, yBase-height);
    painter.drawLine(xBase+256+2, yBase, xBase+256+2, yBase-height);

    // left ordinate arrow
    painter.drawLine(xBase, yBase-height, xBase+4, yBase-height+7);
    painter.drawLine(xBase-1, yBase-height, xBase-1-4, yBase-height+7);

    // right ordinate arrow
    painter.drawLine(xBase+256+1, yBase-height, xBase+256+1-4, yBase-height+7);
    painter.drawLine(xBase+256+2, yBase-height, xBase+256+2+4, yBase-height+7);
}



void Histogram::drawBlueHstgrm(int xBase, int yBase, int height)
{
    QPainter painter(this);

    painter.setPen(Qt::darkBlue);

    float max = bwHstgrm[256];

    if (max < redHstgrm[256])
        max = redHstgrm[256];

    if (max < greenHstgrm[256])
        max = greenHstgrm[256];

    if (max < blueHstgrm[256])
        max = blueHstgrm[256];

    // drawing the histogram
    for(int i = 0;i<256;i++)
    {
        painter.drawLine(xBase+1+i, yBase, xBase+1+i,
            yBase-(float)(256./max)*(float)blueHstgrm[i]);
    }

    painter.drawText(xBase, yBase+25, tr("dark"));
    painter.drawText(xBase+225, yBase+25, tr("light"));

    painter.setPen(Qt::black);

    painter.drawText(xBase+20, yBase-height-10, tr("BLUE COMPONENT HISTOGRAM"));

    painter.drawText(xBase+100, yBase+15, tr("Intensity"));
    painter.drawText(xBase-84, yBase-height/2+5, tr("Pixels count"));

    // abscissa
    painter.drawLine(xBase, yBase, xBase+256+1, yBase);
    painter.drawLine(xBase, yBase+1, xBase+256+1, yBase+1);

    // left ordinate
    painter.drawLine(xBase, yBase, xBase, yBase-height);
    painter.drawLine(xBase-1, yBase, xBase-1, yBase-height);

    // right ordinate
    painter.drawLine(xBase+256+1, yBase, xBase+256+1, yBase-height);
    painter.drawLine(xBase+256+2, yBase, xBase+256+2, yBase-height);

    // left ordinate arrow
    painter.drawLine(xBase, yBase-height, xBase+4, yBase-height+7);
    painter.drawLine(xBase-1, yBase-height, xBase-1-4, yBase-height+7);

    // right ordinate arrow
    painter.drawLine(xBase+256+1, yBase-height, xBase+256+1-4, yBase-height+7);
    painter.drawLine(xBase+256+2, yBase-height, xBase+256+2+4, yBase-height+7);
}



int Histogram::getBwHstgrm(int index)
{
    if (index >= 0 && index <= 258)
        return bwHstgrm[index];
    else
        return -2;
}



int Histogram::getRedHstgrm(int index)
{
    if (index >= 0 && index <= 257)
        return redHstgrm[index];
    else
        return -2;
}



int Histogram::getGreenHstgrm(int index)
{
    if (index >= 0 && index <= 257)
        return greenHstgrm[index];
    else
        return -2;
}



int Histogram::getBlueHstgrm(int index)
{
    if (index >= 0 && index <= 257)
        return blueHstgrm[index];
    else
        return -2;
}

调用部分

主窗口中建立了一个Histogram菜单项(Action),以下是触发Action后的操作

/******************************************************************************
 *                           绘制图像直方图
 *****************************************************************************/
void MainWindow::on_actionHistogram_triggered()
{

    QDialog * hstgrmDialog = new QDialog(this);
    QScrollArea * scrollArea = new QScrollArea(hstgrmDialog);
    Histogram * hstgrm = new Histogram(scrollArea);
    hstgrm->computeHstgrm(rightImage->imageObject());

    if (hstgrm == NULL)
        return;


    scrollArea->setWidget(hstgrm);

    QHBoxLayout * layout = new QHBoxLayout;
    layout->addWidget(scrollArea);
    hstgrmDialog->setLayout(layout);

    hstgrm->resize(800, 780);
    hstgrmDialog->setFixedWidth(820);
    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scrollArea->adjustSize();

    hstgrmDialog->setWindowTitle("Histogram - ImageQt");

    hstgrmDialog->show();
}

效果图

[caption id="attachment_1667" align="aligncenter" width="848"] 直方图[/caption]