使用OpenCV進(jìn)行圖像二值化與灰度化
相關(guān)概念
「二值圖像」(Binary Image)是一種只包含兩種顏色(通常是黑色和白色)的圖像。在二值圖像中,每個(gè)像素要么是0(表示黑色),要么是255(表示白色),沒(méi)有中間灰度級(jí)別。
二值圖像主要用于簡(jiǎn)化圖像處理和分析過(guò)程,因?yàn)樗话瑑煞N顏色,使得圖像處理算法更加簡(jiǎn)單、快速。例如,在文字識(shí)別、條形碼讀取等應(yīng)用中,二值圖像可以大大簡(jiǎn)化圖像處理和識(shí)別的過(guò)程。
二值圖像可以通過(guò)多種方法生成,包括閾值分割、迭代閾值分割、Otsu閾值法等。這些方法通常將原始圖像中的像素值與某個(gè)閾值進(jìn)行比較,根據(jù)比較結(jié)果將像素設(shè)置為黑色或白色。
二值圖像的生成通常用于計(jì)算機(jī)視覺(jué)和圖像處理領(lǐng)域,以簡(jiǎn)化圖像處理和分析的過(guò)程。
「灰度圖像」(Grayscale Image)是每個(gè)像素只有一個(gè)采樣顏色的圖像,通常顯示為從最暗的黑色到最亮的白色的灰度?;叶葓D像與二值圖像不同,在計(jì)算機(jī)圖像領(lǐng)域中,二值圖像只有黑色與白色兩種顏色,而灰度圖像在黑色與白色之間還有許多級(jí)的顏色深度。
灰度圖像通常是測(cè)量每個(gè)像素的亮度得到的,用于顯示的灰度圖像通常用每個(gè)采樣像素8位的非線性尺度來(lái)保存,這樣可以有256級(jí)灰度。
灰度圖像在圖像處理中常用于簡(jiǎn)化圖像處理和分析過(guò)程,因?yàn)樗话环N顏色通道,使得算法更加簡(jiǎn)單和快速。
「彩色圖像」(Color Image)彩色圖像是一種能夠顯示顏色信息的圖像,通常由紅、綠、藍(lán)三個(gè)顏色通道組合而成。每個(gè)通道的顏色強(qiáng)度范圍從0到255,其中0表示該顏色完全缺失,255表示該顏色完全飽和。通過(guò)組合不同強(qiáng)度的三個(gè)通道,可以得到幾乎所有的顏色。
彩色圖像是數(shù)字圖像處理和計(jì)算機(jī)視覺(jué)領(lǐng)域中的常見(jiàn)形式,廣泛應(yīng)用于攝影、視頻、動(dòng)畫(huà)和網(wǎng)頁(yè)設(shè)計(jì)等領(lǐng)域。在數(shù)字圖像處理中,彩色圖像的處理和分析通常比灰度圖像更加復(fù)雜,因?yàn)樾枰瑫r(shí)處理三個(gè)顏色通道。
彩色圖像的優(yōu)點(diǎn)是可以顯示顏色信息,更加真實(shí)地反映現(xiàn)實(shí)世界。然而,由于需要更多的存儲(chǔ)空間和處理時(shí)間,彩色圖像的處理速度通常比灰度圖像慢。
「圖像灰度化」(Image Grayscale) 是將彩色圖像轉(zhuǎn)換為灰度圖像的過(guò)程。在灰度圖像中,每個(gè)像素只包含一個(gè)灰度值,而不是彩色圖像中的紅、綠和藍(lán)三個(gè)通道?;叶葓D像通常用于簡(jiǎn)化圖像處理和分析,因?yàn)樗鼈冎话炼刃畔?,而沒(méi)有顏色信息。
灰度化的好處是相較于彩色圖像灰度圖像占內(nèi)存更小,運(yùn)行速度更快;灰度圖像后可以在視覺(jué)上增加對(duì)比,突出目標(biāo)區(qū)域?;叶然膽?yīng)用包括圖像處理、計(jì)算機(jī)視覺(jué)、模式識(shí)別等領(lǐng)域。
灰度圖像是二值圖像的一種特例,二值圖像通過(guò)比較閾值將像素設(shè)置為黑色或白色?;叶然幚碛腥N常用方法:最大值法、平均值法和加權(quán)平均法。最大值法是直接取R、B、G三個(gè)分量中數(shù)值最大的分量的數(shù)值(0視為最小,255視為最大);平均值法是取R、B、G三個(gè)分量中數(shù)值的均值;加權(quán)平均法則是根據(jù)人眼對(duì)不同顏色的敏感度不同,給不同的顏色通道賦予不同的權(quán)重。
「圖像二值化」(Image Binarization)是將圖像上的像素點(diǎn)的灰度值設(shè)置為0或255,也就是將整個(gè)圖像呈現(xiàn)出明顯的黑白效果的過(guò)程。二值化圖像中數(shù)據(jù)量大為減少,從而能凸顯出目標(biāo)的輪廓。要得到二值化圖像,首先要把圖像灰度化,然后將256個(gè)亮度等級(jí)的灰度圖像通過(guò)適當(dāng)?shù)拈撝颠x取而獲得仍然可以反映圖像整體和局部特征的二值化圖像。所有灰度大于或等于閾值的像素被判定為屬于特定物體,其灰度值為255,否則這些像素點(diǎn)被排除在物體區(qū)域以外,灰度值為0,表示背景或者例外的物體區(qū)域。
比較常用的二值化方法有:簡(jiǎn)單二值法,平均值法,雙峰法和OTSU法等。
二值化是圖像分割的一種最簡(jiǎn)單的方法,廣泛應(yīng)用于計(jì)算機(jī)視覺(jué)領(lǐng)域。
灰度化方法
- 最大值法:將彩色圖像中的三分量亮度的最大值作為灰度圖的灰度值。
圖片
- 平均值法:將彩色圖像中的三分量亮度求平均得到一個(gè)灰度值。
圖片
- 加權(quán)平均法:根據(jù)人眼對(duì)R,G,B三通道的敏感度,按照一定權(quán)值進(jìn)行加權(quán)平均得到灰度值。
圖片
- 浮點(diǎn)灰度法:將紅、綠、藍(lán)三個(gè)顏色通道乘以不同的浮點(diǎn)數(shù)權(quán)重,其中 RGB 的權(quán)重總和為 1,得到一個(gè)灰度值。
圖片
- 整數(shù)灰度法:避免浮點(diǎn)數(shù)運(yùn)算使用整數(shù)算法,其中 RGB 的權(quán)重總和為 100,得到一個(gè)灰度值。
圖片
- 移位灰度法:移位計(jì)算比整數(shù)灰度法處理速度更快。
圖片
- 單通道法:僅取綠色作為灰度值。
圖片
灰度方法示例:
//進(jìn)行灰度
mBitmap?.run {
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
val srcMat = Mat()
val dstMat = Mat()
Utils.bitmapToMat(this, srcMat)
Imgproc.cvtColor(srcMat, dstMat, Imgproc.COLOR_BGRA2GRAY)
Utils.matToBitmap(dstMat, bitmap)
runOnUiThread { mBinding.ivImage.setImageBitmap(bitmap) }
srcMat.release()
dstMat.release()
}
圖片
二值化方法
- 全局閾值法:該方法假設(shè)在整個(gè)圖像范圍內(nèi),亮度高于某個(gè)閾值的像素應(yīng)被標(biāo)記成前景(白色),而亮度低于該閾值的像素則應(yīng)被標(biāo)記成背景(黑色)。
- otsu閾值法:這是一種根據(jù)直方圖的自適應(yīng)閾值選擇算法,使用的閾值可使目標(biāo)與背景之間的差異達(dá)到最大。
- 局部閾值法:該方法不像全局閾值法將整張圖像劃分為前景和背景,而是根據(jù)每個(gè)像素周?chē)徲蛄炼茸兓瘉?lái)確定其屬于前景還是背景。這種方法通常用于具有光照不均、噪聲較多、紋理粗糙等情況下的圖像二值化。
- 自適應(yīng)閾值法:該方法將每個(gè)像素的閾值設(shè)置為與其鄰域內(nèi)像素的平均值或加權(quán)平均值相關(guān)的值。這種方法通常用于灰度圖像中需要提取一些特殊特征的情況下。
- 基于形態(tài)學(xué)操作的局部二值化法:該方法是在閾值法的基礎(chǔ)上,對(duì)圖像的不同區(qū)域設(shè)定不同的閾值,以更好地反映圖像的局部特征。
- 基于聚類分析的二值化法:該方法是將像素點(diǎn)的灰度值分為兩個(gè)簇,然后分別計(jì)算兩個(gè)簇的均值,將均值作為閾值來(lái)進(jìn)行處理。
- 基于邊緣檢測(cè)的二值化法:該方法是在圖像進(jìn)行邊緣檢測(cè)之后,將邊緣像素設(shè)為白色,其他像素設(shè)為黑色,以實(shí)現(xiàn)圖像的二值化。
在 OpenCV 中,通過(guò)使用閾值分割 threshold() 函數(shù)、彩色圖像分割 inRange() 函數(shù)以及邊緣檢測(cè) Canny() 函數(shù)都可以實(shí)現(xiàn)圖像二值化。
OpenCV中最簡(jiǎn)單的實(shí)現(xiàn)方式,先把圖像灰度化,然后對(duì)灰度圖像中的每個(gè)像素進(jìn)行遍歷,根據(jù)它的像素值是否大于一個(gè)固定的閾值,對(duì)輸出圖像對(duì)應(yīng)位置的像素賦予不同的值。公式如下:
圖片
二值化方法示例:
mBitmap?.run {
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
//先灰度
val srcMat = Mat()
val dstMat = Mat()
Utils.bitmapToMat(this, srcMat)
Imgproc.cvtColor(srcMat, dstMat, Imgproc.COLOR_BGRA2GRAY)
val resultMat = Mat()
Imgproc.threshold(dstMat, resultMat, 100.0, 255.0, Imgproc.THRESH_BINARY)
Utils.matToBitmap(resultMat, bitmap)
runOnUiThread { mBinding.ivImage.setImageBitmap(bitmap) }
srcMat.release()
dstMat.release()
resultMat.release()
}
圖片
完整示例
<?xml versinotallow="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.TestActivity">
<ImageView
android:id="@+id/iv_image"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<Button
android:id="@+id/btn_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="加載圖片"
android:textSize="16sp" />
<Button
android:id="@+id/btn_gray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:text="圖片灰度化"
android:textSize="16sp" />
<Button
android:id="@+id/btn_binarization"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:text="圖片二值化"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
class TestActivity : AppCompatActivity() {
private val TAG = MainActivity::class.java.simpleName
private lateinit var mBinding: ActivityTestBinding
private var mBitmap: Bitmap? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityTestBinding.inflate(layoutInflater)
setContentView(mBinding.root)
//初始化OpenCV
val initState = OpenCVLoader.initLocal()
Log.d(TAG, "onCreate: OpenCV初始化$initState")
mBinding.btnLoad.setOnClickListener {
val intent = Intent()
intent.setType("image/*")
intent.setAction(Intent.ACTION_GET_CONTENT)
startActivityForResult(intent, 20240104)
}
mBinding.btnGray.setOnClickListener {
if (mBitmap == null) {
return@setOnClickListener
}
//進(jìn)行灰度
mBitmap?.run {
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
val srcMat = Mat()
val dstMat = Mat()
Utils.bitmapToMat(this, srcMat)
Imgproc.cvtColor(srcMat, dstMat, Imgproc.COLOR_BGRA2GRAY)
Utils.matToBitmap(dstMat, bitmap)
runOnUiThread { mBinding.ivImage.setImageBitmap(bitmap) }
srcMat.release()
dstMat.release()
}
}
mBinding.btnBinarization.setOnClickListener {
if (mBitmap == null) {
return@setOnClickListener
}
mBitmap?.run {
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
//先灰度
val srcMat = Mat()
val dstMat = Mat()
Utils.bitmapToMat(this, srcMat)
Imgproc.cvtColor(srcMat, dstMat, Imgproc.COLOR_BGRA2GRAY)
val resultMat = Mat()
Imgproc.threshold(dstMat, resultMat, 100.0, 255.0, Imgproc.THRESH_BINARY)
Utils.matToBitmap(resultMat, bitmap)
runOnUiThread { mBinding.ivImage.setImageBitmap(bitmap) }
srcMat.release()
dstMat.release()
resultMat.release()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 20240104 && resultCode == RESULT_OK && data != null) {
data.data?.run {
mBitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(this))
}
mBitmap?.run {
mBinding.ivImage.setImageBitmap(this)
}
}
}
}
總結(jié)
圖像二值化是將圖像中的像素點(diǎn)設(shè)置為0或255,從而實(shí)現(xiàn)黑白效果的過(guò)程。通過(guò)適當(dāng)?shù)拈撝颠x取,可以將灰度圖像中的像素分為兩類,一類被認(rèn)為是前景(目標(biāo)),另一類被認(rèn)為是背景。這樣可以使圖像數(shù)據(jù)量減小,同時(shí)凸顯出目標(biāo)的輪廓。
灰度化是將彩色圖像轉(zhuǎn)換為灰度圖像的過(guò)程。在灰度圖像中,每個(gè)像素只包含一個(gè)灰度值,而不是彩色圖像中的紅、綠和藍(lán)三個(gè)通道。灰度圖像通常用于簡(jiǎn)化圖像處理和分析,因?yàn)樗鼈冎话炼刃畔ⅲ鴽](méi)有顏色信息。
灰度圖像的每個(gè)像素可以用8位來(lái)表示,因此有0-255個(gè)灰度值。而二值圖像中,像素只有兩種狀態(tài):黑色(0)和白色(255)。
二值化是將灰度圖像轉(zhuǎn)換為黑白二值圖像的過(guò)程,而灰度化是將彩色圖像轉(zhuǎn)換為灰度圖像的過(guò)程。在OpenCV中,可以使用不同的閾值處理方法來(lái)實(shí)現(xiàn)圖像的二值化和灰度化。