您的位置:首页 > 编程语言 > Python开发

Python语言opencv使用笔记(九)(图像直方图)

2018-01-09 11:05 696 查看
<div class="article_content tracking-ad" id="article_content" data-mod="popu_307" data-dsm="post">

<div class="markdown_views"><h2 id="一图像直方图"><a name="t0"></a>(一)图像直方图</h2>
<p>图像的构成是有像素点构成的,每个像素点的值代表着该点的颜色(灰度图或者彩色图)。所谓直方图就是对图像的中的这些像素点的值进行统计,得到一个统一的整体的灰度概念。直方图的好处就在于可以清晰了解图像的整体灰度分布,这对于后面依据直方图处理图像来说至关重要。</p>
<p>一般情况下直方图都是灰度图像,直方图x轴是灰度值(一般0~255),y轴就是图像中每一个灰度级对应的像素点的个数。</p>
<p>那么如何获得图像的直方图?首先来了解绘制直方图需要的一些量:灰度级,正常情况下就是0-255共256个灰度级,从最黑一直到最亮(白)(也有可能统计其中的某部分灰度范围),那么每一个灰度级对应一个数来储存该灰度对应的点数目。也就是说直方图其实就是一个1*m(灰度级)的一个数组而已。但是有的时候我们不希望一个一个灰度的递增,比如现在我想15个灰度一起作为一个灰度级来花直方图,这个时候我们可能只需要1*(m/15)这样一个数组就够了。那么这里的15就是直方图的间隔宽度了。</p>
<p>Opencv给我们提供的函数是cv2.calcHist(),该函数有5个参数:</p>
<ul>

<li>image输入图像,传入时应该用中括号[]括起来</li>

<li>channels::传入图像的通道,如果是灰度图像,那就不用说了,只有一个通道,值为0,如果是彩色图像(有3个通道),那么值为0,1,2,中选择一个,对应着BGR各个通道。这个值也得用[]传入。</li>

<li>mask:掩膜图像。如果统计整幅图,那么为none。主要是如果要统计部分图的直方图,就得构造相应的炎掩膜来计算。</li>

<li>histSize:灰度级的个数,需要中括号,比如[256]</li>

<li>ranges:像素值的范围,通常[0,256],有的图像如果不是0-256,比如说你来回各种变换导致像素值负值、很大,则需要调整后才可以。</li>

</ul>
<p>除此之外,强大的numpy也有函数用于统计直方图的,通用的一个函数np.histogram,还有一个函数是np.bincount()(用于以为统计直方图,速度更快)。这三个方式的传入参数基本上差不多,不同的是opencv自带的需要中括号括起来。 <br>

对于直方图的显示也是比较简单的,直接plt.plot()就可以。一个实例如下:</p>

<pre class="prettyprint" name="code"><code class="hljs python has-numbering"><span class="hljs-keyword">import</span> cv2

<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
img = cv2.imread(<span class="hljs-string">'flower.jpg'</span>,<span class="hljs-number">0</span>) <span class="hljs-comment">#直接读为灰度图像</span>

<span class="hljs-comment">#opencv方法读取-cv2.calcHist(速度最快)</span>

<span class="hljs-comment">#图像,通道[0]-灰度图,掩膜-无,灰度级,像素范围</span>

hist_cv = cv2.calcHist([img],[<span class="hljs-number">0</span>],<span class="hljs-keyword">None</span>,[<span class="hljs-number">256</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">256</span>])

<span class="hljs-comment">#numpy方法读取-np.histogram()</span>

hist_np,bins = np.histogram(img.ravel(),<span class="hljs-number">256</span>,[<span class="hljs-number">0</span>,<span class="hljs-number">256</span>])

<span class="hljs-comment">#numpy的另一种方法读取-np.bincount()(速度=10倍法2)</span>

hist_np2 = np.bincount(img.ravel(),minlength=<span class="hljs-number">256</span>)

plt.subplot(<span class="hljs-number">221</span>),plt.imshow(img,<span class="hljs-string">'gray'</span>)

plt.subplot(<span class="hljs-number">222</span>),plt.plot(hist_cv)

plt.subplot(<span class="hljs-number">223</span>),plt.plot(hist_np)

plt.subplot(<span class="hljs-number">224</span>),plt.plot(hist_np2)</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul></pre>
<p><img title="" alt="这里写图片描述" src="http://img.blog.csdn.net/20150714174631743"></p>
<p>现在来考虑opencv的直方图函数中掩膜的使用,这个掩膜就是一个区域大小,表示你接下来的直方图统计就是这个区域的像素统计。一个例子如下:</p>

<pre class="prettyprint" name="code"><code class="hljs python has-numbering"><span class="hljs-keyword">import</span> cv2

<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt

img = cv2.imread(<span class="hljs-string">'flower.jpg'</span>,<span class="hljs-number">0</span>) <span class="hljs-comment">#直接读为灰度图像</span>

mask = np.zeros(img.shape[:<span class="hljs-number">2</span>],np.uint8)

mask[<span class="hljs-number">100</span>:<span class="hljs-number">200</span>,<span class="hljs-number">100</span>:<span class="hljs-number">200</span>] = <span class="hljs-number">255</span>

masked_img = cv2.bitwise_and(img,img,mask=mask)
<span class="hljs-comment">#opencv方法读取-cv2.calcHist(速度最快)</span>

<span class="hljs-comment">#图像,通道[0]-灰度图,掩膜-无,灰度级,像素范围</span>

hist_full = cv2.calcHist([img],[<span class="hljs-number">0</spa
4000
n>],<span class="hljs-keyword">None</span>,[<span class="hljs-number">256</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">256</span>])

hist_mask = cv2.calcHist([img],[<span class="hljs-number">0</span>],mask,[<span class="hljs-number">256</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">256</span>])
plt.subplot(<span class="hljs-number">221</span>),plt.imshow(img,<span class="hljs-string">'gray'</span>)

plt.subplot(<span class="hljs-number">222</span>),plt.imshow(mask,<span class="hljs-string">'gray'</span>)

plt.subplot(<span class="hljs-number">223</span>),plt.imshow(masked_img,<span class="hljs-string">'gray'</span>)

plt.subplot(<span class="hljs-number">224</span>),plt.plot(hist_full),plt.plot(hist_mask)</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul></pre>
<p><img title="" alt="这里写图片描述" src="http://img.blog.csdn.net/20150714174707917"></p>

<h2 id="二直方图均衡化"><a name="t1"></a>(二)直方图均衡化</h2>
<p>图像的直方图是对图像对比度效果上的一种处理,旨在使得图像整体效果均匀,黑与白之间的各个像素级之间的点更均匀一点。 <br>

直方图均衡化只要包括三个步骤:</p>
<ol>

<li>统计直方图中每个灰度级出现的次数;</li>

<li>计算累计归一化直方图;</li>

<li>重新计算像素点的像素值;</li>

</ol>
<p>关于原理的详细部分给一个参考: </p>
<p><strong><em><a href="http://blog.csdn.net/rushkid02/article/details/9178117" target="_blank">直方图均衡化原理</a></em></strong></p>
<p>百度百科的解释也很棒 <br>

<a href="http://baike.baidu.com/link?url=RUjahehgkTMDGKwAEyMsHyeMyWWTw9a0KUx2CzLbXtxdZyoF6zqDbJsfEffUQYAwvr7kD9p6cbOxJGYGk1nkZq" target="_blank">http://baike.baidu.com/link?url=RUjahehgkTMDGKwAEyMsHyeMyWWTw9a0KUx2CzLbXtxdZyoF6zqDbJsfEffUQYAwvr7kD9p6cbOxJGYGk1nkZq</a></p>
<p>在opencv有专门函数对直方图进行均衡化使用的函数就是cv2.equalizeHist().一个实例如:</p>

<pre class="prettyprint" name="code"><code class="hljs python has-numbering"><span class="hljs-keyword">import</span> cv2

<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
img = cv2.imread(<span class="hljs-string">'flower.jpg'</span>,<span class="hljs-number">0</span>) <span class="hljs-comment">#直接读为灰度图像</span>

res = cv2.equalizeHist(img)
plt.subplot(<span class="hljs-number">121</span>),plt.imshow(img,<span class="hljs-string">'gray'</span>)

plt.subplot(<span class="hljs-number">122</span>),plt.imshow(res,<span class="hljs-string">'gray'</span>)</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul></pre>
<p><img title="" alt="这里写图片描述" src="http://img.blog.csdn.net/20150714174935230"></p>
<p>上述的直方图均衡化可以可能到是一种全局意义上的均衡化,但是有的时候这种操作并不是很好,会把某些不该调整的部分给调整了。Opencv中还有一种直方图均衡化,它是一种局部局部来的均衡化,也就是是说把整个图像分成许多小块(比如按10*10作为一个小块),那么对每个小块进行均衡化。这种方法主要对于图像直方图不是那么单一的(比如存在多峰情况)图像比较实用。Opencv中将这种方法称之为CLAHE,使用到的函数就是cv2.createCLAHE(),一个实例如下:</p>

<pre class="prettyprint" name="code"><code class="hljs python has-numbering"><span class="hljs-keyword">import</span> cv2

<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
img = cv2.imread(<span class="hljs-string">'flower.jpg'</span>,<span class="hljs-number">0</span>) <span class="hljs-comment">#直接读为灰度图像</span>

clahe = cv2.createCLAHE(clipLimit=<span class="hljs-number">2</span>,tileGridSize=(<span class="hljs-number">10</span>,<span class="hljs-number">10</span>))

cl1 = clahe.apply(img)
plt.subplot(<span class="hljs-number">121</span>),plt.imshow(img,<span class="hljs-string">'gray'</span>)

plt.subplot(<span class="hljs-number">122</span>),plt.imshow(cl1,<span class="hljs-string">'gray'</span>)</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul></pre>
<p><img title="" alt="这里写图片描述" src="http://img.blog.csdn.net/20150714175021176"> <br>

可以看到,相对于全局的直方图均衡化,这个局部的均衡化似乎得到的效果更自然一点。</p></div>

<script type="text/javascript">

$(function () {

$('pre.prettyprint code').each(function () {

var lines = $(this).text().split('\n').length;

var $numbering = $('<ul/>').addClass('pre-numbering').hide();

$(this).addClass('has-numbering').parent().append($numbering);

for (i = 1; i <= lines; i++) {

$numbering.append($('<li/>').text(i));

};

$numbering.fadeIn(1700);

});

});

</script>

</div>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息