Opencv笔记(二十)——直方图(二)
直方图均衡化
原理:
想象一下如果一副图像中的大多是像素点的像素值都集中在一个像素值范围之内会怎样呢?例如,如果一幅图片整体很亮,那所有的像素值应该都会很高。但是一副高质量的图像的像素值分布应该很广泛。所以你应该把它的直方图做一个横向拉伸(如下图),这就是直方图均衡化要做的事情。通常情况下这种操作会改善图像的对比度。直方图均衡化后面潜在的数学原理是一个分布(输入的亮度直方图)被映射到另一个分布(一个更宽,理想统一的亮度值分布),映射函数是一个累积分布函数。对于连续分布,结果将是准确的均衡化。在equalizeHist中,原始图像及目标图像必须是单通道,大小相同的8位图像,对于彩色图像,必须先将每个通道分开,再分别进行直方图均衡化处理,然后将通道合并形成新的图像。
# coding=utf-8
import cv2
import numpy as np
img = cv2.imread("/home/wl/4.jpg",0)
equ = cv2.equalizeHist(img)#灰度图像直方图均衡化
while(1):
cv2.imshow("2",equ)
cv2.imshow("1", img)
cv2.imwrite("/home/wl/baocun1.jpg", img)
cv2.imwrite("/home/wl/baocun2.jpg", equ)
k = cv2.waitKey(1) & 0XFF
if k==ord('q'):
break;
cv2.destroyAllWindows()
原图:
均值化后的图:
CLAHE 有限对比适应性直方图均衡化
的确在进行完直方图均衡化之后,图片背景的对比度被改变了。但可能会由于太亮而丢失了很多信息。造成这种结果的根本原因在于这幅图像的直方图并不是集中在某一个区域。为了解决这个问题,我们需要使用自适应的直方图均衡化。这种情况下,整幅图像会被分成很多块这些小块被称为“tiles”(在 OpenCV 中 tiles 的大小默认是 8x8),然后再对每一个小块分别进行直方图均衡化(跟前面类似)。所以在每一个的区域中,直方图会集中在某一个小的区域中(除非有噪声干扰)。如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的 bin 超过对比度的上限的话,就把其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。最后,为了去除每一个小块之间“人造的”(由于算法造成)边界,再使用双线性差值,对小块进行缝合。
import cv2
img = cv2.imread("/home/wl/4.jpg",0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
效果图:
2D直方图
在前面的部分我们介绍了如何绘制一维直方图,之所以称为一维,是因为我们只考虑了图像的一个特征:灰度值。但是在 2D 直方图中我们就要考虑两个图像特征。对于彩色图像的直方图通常情况下我们需要考虑每个的色调(Hue)和饱和度(Saturation)。根据这两个特征绘制 2D 直方图。
使用函数 cv2.calcHist(),函数的参数要做如下修改:
- channels=[0,1] 因为我们需要同时处理 H 和 S 两个通道。
- bins=[180,256]H 通道为 180,S 通道为 256。
- range=[0,180,0,256]H 的取值范围在 0 到 180,S 的取值范围在 0 到 256。
# coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("/home/wl/4.jpg")
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
plt.imshow(hist,interpolation = 'nearest')#nearest插值参数
plt.show()
Numpy 中 2D 直方图
Numpy 同样提供了绘制 2D 直方图的函数:np.histogram2d()。
# coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("/home/wl/4.jpg")
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
h=hsv[:,:,0]
s=hsv[:,:,1]
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
plt.imshow(hist,interpolation = 'nearest')
plt.show()
直方图反向投影
原理:
反向投影可以用来做图像分割,寻找感兴趣区间。它会输出与输入图像大小相同的图像,每一个像素值代表了输入图像上对应点属于目标对象的概率,简言之,输出图像中像素值越高的点越可能代表想要查找的目标。直方图投影经常与camshift(追踪算法)算法一起使用。算法实现的方法,首先要为包含我们感兴趣区域的图像建立直方图(样例要找一片草坪,其他的不要)。被查找的对象最好是占据整个图像(图像里全是草坪)。最好使用颜色直方图,物体的颜色信息比灰度图像更容易被分割和识别。再将颜色直方图投影到输入图像查找目标,也就是找到输入图像中每一个像素点的像素值在直方图中对应的概率,这样就得到一个概率图像,最后设置适当的阈值对概率图像进行二值化。
OpenCV 提供的函数 cv2.calcBackProject() 可以用来做直方图反向投影。它的参数与函数 cv2.calcHist 的参数基本相同。其中的一个参数是我们要查找目标的直方图。同样再使用目标的直方图做反向投影之前我们应该先对其做归一化处理。返回的结果是一个概率图像,我们再使用一个圆盘形卷积核对其做卷操作,最后使用阈值进行二值化。下面就是代码和结果:
# coding=utf-8
import cv2
import numpy as np
#roi图片,就想要找的的图片
roi = cv2.imread('1.jpg')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
#目标搜索图片
target = cv2.imread('2.jpg')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
#计算目标直方图
roihist = cv2.calcHist([hsv],[0,1],None,[180,256],[0,180,0,256])
#归一化,参数为原图像和输出图像,归一化后值全部在2到255范围
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
#卷积连接分散的点
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
dst = cv2.filter2D(dst,-1,disc)
ret,thresh = cv2.threshold(dst,50,255,0)
#使用merge变成通道图像
thresh = cv2.merge((thresh,thresh,thresh))
#蒙板
res = cv2.bitwise_and(target,thresh)
#矩阵按列合并,就是把target,thresh和res三个图片横着拼在一起
res = np.hstack((target,thresh,res))
cv2.imwrite('res.jpg',res)
#显示图像
cv2.imshow('1',res)
cv2.waitKey(0)
原图:
结果:
Opencv笔记(二十)——直方图(二)的更多相关文章
- OpenCV-Python 直方图-3:二维直方图 | 二十八
目标 在本章中,我们将学习查找和绘制2D直方图.这将在以后的章节中有所帮助. 介绍 在第一篇文章中,我们计算并绘制了一维直方图. 之所以称为一维,是因为我们仅考虑一个特征,即像素的灰度强度值. 但是在 ...
- Opencv笔记(十九)——直方图(一)
直方图概念 图像的构成是有像素点构成的,每个像素点的值代表着该点的颜色(灰度图或者彩色图).所谓直方图就是对图像的中的这些像素点的值进行统计,得到一个统一的整体的灰度概念.一般情况下直方图都是灰度图像 ...
- Opencv笔记(十二)——形态学转换
学习目标: 学习不同的形态学操作,例如腐蚀,膨胀,开运算,闭运算等 我们要学习的函数有: cv2.erode(), cv2.dilate(), cv2.morphologyEx()等 原理简介: 形态 ...
- Opencv笔记(十六)——认识轮廓
什么是轮廓? 轮廓可以简单认为成连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度.轮廓在形状分析和物体的检测和识别中很有用.谈起轮廓不免想到边缘,它们确实很像.简单的说,轮廓是连续的,边缘并 ...
- Opencv笔记(十)——卷积基础
卷积 什么是二维卷积呢?看下面一张图就一目了然: 卷积就是循环对图像跟一个核逐个元素相乘再求和得到另外一副图像的操作,比如结果图中第一个元素5是怎么算的呢?原图中3×3的区域与3×3的 ...
- IOS开发---菜鸟学习之路--(二十)-二维码扫描功能的实现
本章将讲解如何实现二维码扫描的功能 首先在github上下载ZBar SDK地址https://github.com/bmorton/ZBarSDK 然后将如下的相关类库添加进去 AVFoundati ...
- Opencv笔记(十五)——图像金字塔
参考文献 目标 学习图像金字塔 学习函数cv2.pyrUp()和cv2.pyrDown() 原理 当我们需要将图像转换到另一个尺寸的时候, 有两种可能,一种是放大图像,另一种是缩小图像.尽管在Open ...
- Opencv笔记(十四)——边缘检测算法canny
简介 Canny 边缘检测算法 是 John F. Canny 于 1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的 最优算法,它是由很多步构成的算法. 最优边缘检测的三个主要评价 ...
- Dynamic CRM 2013学习笔记(二十)字段改变事件的二种实现方法
CRM里有二种方式实现字段change事件,一种是在form里,一种完全通过js来实现.本文介绍下二者的用途及区别. 1. Form里用法 这种方式估计其实也是添加一个js的function. 这种方 ...
- Dynamic CRM 2013学习笔记(二十六)报表设计:Reporting Service报表 动态参数、参数多选全选、动态列、动态显示行字体颜色
上次介绍过CRM里开始报表的一些注意事项:Dynamic CRM 2013学习笔记(十五)报表入门.开发工具及注意事项,本文继续介绍报表里的一些动态效果:动态显示参数,参数是从数据库里查询出来的:参数 ...
随机推荐
- 自定义环形进度条RoundProgressBar
一.效果图: Canvas画圆环说明: 圆环宽度不必在意,只是画笔宽度设置后达到的效果. 二.实现步骤 1.自定义View-RoundProgressBar 2.设置属性resources(decle ...
- Essay写作的六大黄金法则以及四大禁区
虽然Essay这么难写,但是,也有一些可以拿高分的准则,本文小编就为大家分享高分Essay写作必知黄金法则,希望对想要在Essay拿高分的留学生小伙伴们有些帮助. 黄金法则1.关注相关问题的重点词汇 ...
- sed使用案例
简介: sed是一种流编辑器,它是文本处理中非常重要的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 ...
- C++交换两个变量值的方法
简单地列一下交换两个变量值地几种方法. 1.通过第三方实现,这一种也是最最最常见普通的方法: void swap(int *a, int *b) { int tmp = *a; *a = *b; *b ...
- 【收藏】免费开源好看的bootstrap后台模板
1.ace admin github:https://github.com/bopoda/acedemo:http://ace.jeka.by/ 2.CoreUI jQuery.Angular.Rea ...
- Java连载70-冒泡算法、选择算法
一.冒泡排序 1.也就是依次选出最大的放在最后面 package com.bjpowernode.java_learning; public class D70_1_BubbleSort { pu ...
- handler method 参数绑定常用注解
handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类: A.处理requet uri 部分(这里指uri template中variable,不含q ...
- 吴裕雄--天生自然 JAVASCRIPT开发学习:DOM EventListener
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- PAT Advance 1119 Pre- and Post-order Traversals (30) [树的遍历,前序后序转中序]
题目 Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree c ...
- MyBatis中foreach传入参数为数组
一.当只有一个参数,并且这个参数是数组时 接口方法的参数不需要添加@Param注释,collection="array" 示例 接口的方法 void deleteMulti(Str ...