Android OpenCV(十四):图像直方图

1,298 阅读2分钟

图像直方图

图像直方图是统计图像中每个灰度值的个数,之后将图像灰度值作为横轴,以灰度值个数或者灰度值所占比率作为纵轴绘制的统计图。通过直方图可以看出图像中哪些灰度值数目较多,哪些较少。

  • 直方图是图像中像素强度分布的图形表达方式。
  • 直方图统计了每一个强度值所具有的像素个数。

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()
    }
}

效果

图像直方图
图像直方图

源码

github.com/onlyloveyd/…

本文使用 mdnice 排版