图像直方图
图像直方图是统计图像中每个灰度值的个数,之后将图像灰度值作为横轴,以灰度值个数或者灰度值所占比率作为纵轴绘制的统计图。通过直方图可以看出图像中哪些灰度值数目较多,哪些较少。
- 直方图是图像中像素强度分布的图形表达方式。
- 直方图统计了每一个强度值所具有的像素个数。
API
public static void calcHist(List<Mat> images, MatOfInt channels, Mat mask, Mat hist, MatOfInt histSize, MatOfFloat ranges, boolean accumulate)
- 参数一:images,待统计直方图的图像数组,数组中所有的图像应具有相同的尺寸和数据类型,并且数据类型只能是CV_8U、CV_16U和CV_32F三种中的一种,但是不同图像的通道数可以不同。
- 参数二:channels,需要统计的通道索引数组,第一个图像的通道索引从0到images[0].channels()-1,第二个图像通道索引从images[0].channels()到images[0].channels()+ images[1].channels()-1,以此类推。
- 参数三:mask,可选的操作掩码,如果是空矩阵则表示图像中所有位置的像素都计入直方图中,如果矩阵不为空,则必须与输入图像尺寸相同且数据类型为CV_8U。
- 参数四:hist,输出的统计直方图结果
- 参数五:histSize,存放每个维度直方图的数组的尺寸。
- 参数六:ranges,每个图像通道中灰度值的取值范围。
- 参数七:accumulate:是否累积统计直方图的标志,如果累积(true),则统计新图像的直方图时之前图像的统计结果不会被清除,该同能主要用于统计多个图像整体的直方图。
操作
class HistActivity : AppCompatActivity() {
private lateinit var mBinding: ActivityHistBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_hist)
initChart()
mBinding.ivLena.setImageResource(R.drawable.lena)
val bgr = Utils.loadResource(this, R.drawable.lena)
val gray = Mat()
Imgproc.cvtColor(bgr, gray, Imgproc.COLOR_BGR2GRAY)
showMat(mBinding.ivGray, gray)
calHist(gray)
}
private fun initChart() {
mBinding.chartHist.axisLeft.axisMinimum = 0.0F
mBinding.chartHist.axisRight.isEnabled = false
mBinding.chartHist.setDrawGridBackground(false)
mBinding.chartHist.description.isEnabled = false
mBinding.chartHist.xAxis.position = XAxis.XAxisPosition.BOTTOM
}
private fun showMat(view: ImageView, source: Mat) {
val bitmap = Bitmap.createBitmap(source.width(), source.height(), Bitmap.Config.ARGB_8888)
Utils.matToBitmap(source, bitmap)
view.setImageBitmap(bitmap)
}
private fun calHist(gray: Mat) {
val hist = Mat()
val source = listOf(gray)
val mask = Mat()
Imgproc.calcHist(
source,
MatOfInt(0),
mask,
hist,
MatOfInt(256),
MatOfFloat(0F, 255F)
)
val hist_w = 512
val hist_h = 400
val width = 2
val histImage = Mat.zeros(hist_h, hist_w, CvType.CV_8UC3)
for (i in 0 until hist.rows()) {
Imgproc.rectangle(
histImage,
Point(width * (i - 1).toDouble(), (hist_h - 1).toDouble()),
Point((width * i - 1).toDouble(), hist_h - round(hist.get(i, 0)[0] / 10)),
Scalar(255.0, 255.0, 255.0),
-1
)
}
showMat(mBinding.ivHist, histImage)
updateChart(hist)
}
private fun updateChart(hist: Mat) {
val source = FloatArray(256)
for (i in 0 until hist.rows()) {
val result = FloatArray(1)
hist.get(i, 0, result)
source[i] = result[0]
}
val values =
ArrayList<Entry>()
for (i in source.indices) {
values.add(
Entry(
i.toFloat(),
source[i]
)
)
}
val set1 = LineDataSet(values, "直方图")
set1.fillColor = Color.BLACK
set1.axisDependency = AxisDependency.LEFT
set1.color = ColorTemplate.getHoloBlue()
set1.lineWidth = 2f
set1.fillAlpha = 65
set1.fillColor = ColorTemplate.getHoloBlue()
set1.highLightColor = Color.rgb(244, 117, 117)
set1.setDrawCircleHole(false)
set1.setDrawCircles(false)
set1.setDrawFilled(true)
val dataSets = ArrayList<ILineDataSet>()
dataSets.add(set1)
val data = LineData(dataSets)
mBinding.chartHist.data = data
mBinding.chartHist.invalidate()
}
}
效果
源码
本文使用 mdnice 排版