图像腐蚀 java_OpenCV3 图像膨胀 dilate、腐蚀 erode、提取图像中的条形码 JAVA 实现...
關(guān)于 JAVA 學(xué)習(xí) OpenCV 的內(nèi)容,函數(shù)講解,案例代碼內(nèi)容我均整理在 GitHub【OpenCV3-Study-JAVA 】上
下面代碼中所需的項(xiàng)目結(jié)構(gòu),圖片,請?jiān)L問 GitHub 獲取。
代碼展示
package opencv;
import opencv.base.OpenCVStudyBase;
import org.junit.Test;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;
import java.util.List;
/**
* @Author : alexliu
* @Description : 主要學(xué)習(xí)
* 1. 圖像腐蝕
* 2. 圖像膨脹
* 3. 查找條形碼案例
*/
public class StudyTest_8 extends OpenCVStudyBase{
/*
* 腐蝕,膨脹都屬于形態(tài)學(xué)濾波。
*
* 數(shù)學(xué)形態(tài)學(xué)中,基本的運(yùn)算有:
* 二值腐蝕和膨脹
* 二值開閉運(yùn)算
* 骨架抽取
* 極限腐蝕
* 灰值腐蝕和膨脹
* 灰值開閉運(yùn)算
* 灰值形態(tài)學(xué)梯度
* .....
*
*
* 腐蝕,膨脹的主要功能如下:
* 1. 消除噪聲
* 2. 分割(isolate)出獨(dú)立的圖像元素,在圖像中連接(join)相鄰的元素
* 3. 尋找圖像中的明顯的極大值區(qū)域或極小值區(qū)域
* 4. 求出圖像的梯度
*
* 注意:
* 腐蝕和膨脹僅針對`圖像高亮`區(qū)域進(jìn)行操作。
*
*/
private String save_dir = "study-output/study-opencv-8";
/*
* 如何創(chuàng)建腐蝕、膨脹操作的核
*
* 腐蝕和膨脹均有一個(gè) Mat kernel 參數(shù)。這個(gè)參數(shù)就是腐蝕/膨脹操作的核,它是一個(gè)矩陣結(jié)構(gòu)元素(Mat)
* OpenCV 在 Imgproc 包中,提供了 getStructuringElement 的函數(shù),來方便創(chuàng)建腐蝕/膨脹的核
*
* getStructuringElement 原型方法:
* getStructuringElement(int shape, Size ksize, Point anchor)
* getStructuringElement(int shape, Size ksize)
*
* 參數(shù):
* shape : Integer 核的結(jié)構(gòu)類型
* -- C++ 有四種(多一個(gè)用戶自定義),其他語言3種
* -- MORPH_RECT , 一個(gè)矩形結(jié)構(gòu)元素
* -- MORPH_ELLIPSE , 一個(gè)橢圓結(jié)構(gòu)元素
* -- MORPH_CROSS , 一個(gè)十字形結(jié)構(gòu)元素
* ksize : Size 結(jié)構(gòu)元素的大小
* anchor : Point 元素中瞄點(diǎn)的位置。默認(rèn)值 (-1,-1)表示在元素的中心位置。注意:只有十字形結(jié)構(gòu)元素依賴瞄點(diǎn),其他形狀類型僅僅影響結(jié)果的偏移。
*
* 原文:
* shape – Element shape that could be one of the following:
* MORPH_RECT - a rectangular structuring element
* MORPH_ELLIPSE - an elliptic structuring element, that is, a filled ellipse inscribed into the rectangle Rect(0, 0, esize.width, 0.esize.height)
* MORPH_CROSS - a cross-shaped structuring element
* CV_SHAPE_CUSTOM - custom structuring element (OpenCV 1.x API)
* ksize – Size of the structuring element.
* anchor – Anchor position within the element. The default value (-1, -1) means that the anchor is at the center.
* Note that only the shape of a cross-shaped element depends on the anchor position.
* In other cases the anchor just regulates how much the result of the morphological operation is shifted.
*/
/*
* ------------------------------------------------------------------------------------------------------------
*
* 腐蝕
*
* 1. 腐蝕說明:
* 圖像的一部分區(qū)域與指定的核進(jìn)行卷積,求核的最`小`值并賦值給指定區(qū)域。
* 腐蝕可以理解為圖像中`高亮區(qū)域`的'領(lǐng)域縮小'。
* 意思是高亮部分會(huì)被不是高亮部分的像素侵蝕掉,使高亮部分越來越少。
*
* 2. 腐蝕函數(shù)(erode)
* erode 有3個(gè)原型方法
*
* erode(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
* erode(Mat src, Mat dst, Mat kernel, Point anchor, int iterations)
* erode(Mat src, Mat dst, Mat kernel)
*
* 參數(shù):
* src : Mat 輸入圖像 對通道數(shù)無要求,但是 depth 必須是 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 之一
* dst : Mat 輸出圖像,與原圖以上的尺寸與類型
* kernel : Mat 膨脹操作的核 , null 時(shí)表示以當(dāng)前像素為中心 3x3 為單位的核
* 一般使用函數(shù) Imgproc.getStructuringElement 來創(chuàng)建核。該函數(shù)會(huì)返回指定形狀或尺寸的矩陣結(jié)構(gòu)元素。
* anchor : Point 瞄點(diǎn)。根據(jù) kernel(核),處理每個(gè)核的某個(gè)點(diǎn)。 (-1,-1)代表取這個(gè)核的中心位置。
* interations : Integer 迭代 dilate(膨脹)的次數(shù),默認(rèn) 1 。。
* borderType : Integer 推斷圖像外部像素的某種邊界模式,一般不需要這個(gè)參數(shù)。
* borderValue : Scalar 當(dāng) borderType 值為常數(shù)時(shí),區(qū)域的顏色一般不用管,
*
* 腐蝕,一般不需要borderType,borderValue,均有默認(rèn)值。如果需要使用,可參考官網(wǎng)獲取更多信息
*
* ------------------------------------------------------------------------------------------------------------
*/
/**
* 圖像腐蝕處理
* 不做任何處理的圖片
*/
@Test
public void testErodeNomal(){
Mat sourceImage = Imgcodecs.imread(p_test_file_path + "/shufa.png");
//Mat sourceImage = Imgcodecs.imread(test_file_path + "/5cent.jpg",Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
// size 越小,腐蝕的單位越小,圖片越接近原圖
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(30,30));
Mat outImage = new Mat();
//開始腐蝕
Imgproc.erode(sourceImage,outImage,structImage);
this.saveImage(this.save_dir + "/image_process_erode_nomal.png",outImage);
}
/**
* 圖像腐蝕處理
* 灰度處理的圖片
*/
@Test
public void testErodeGray(){
// 由于shufa.png 背景為白色,字體為黑色,在灰度的0-255顯示范圍,看不出變化
// 所以我們換一個(gè)背景圖不是白色的。
Mat sourceImage = Imgcodecs.imread(p_test_file_path + "/shufa-1.jpg",Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE,new Size(30,30));
Mat outImage = new Mat();
Imgproc.erode(sourceImage,outImage,structImage);
this.saveImage(this.save_dir + "/image_process_erode_gray.png",outImage);
}
/**
* 圖像腐蝕處理
* 二值化處理的圖片
*/
@Test
public void testErodeThreshold() {
Mat sourceImage = Imgcodecs.imread(this.p_test_file_path + "/shufa.png");
//二值化處理 cv_8uc1 8位單通道格式
Mat binaryMat = new Mat(sourceImage.height(), sourceImage.width(), CvType.CV_8UC1);
Imgproc.threshold(sourceImage, binaryMat,100, 200, Imgproc.THRESH_BINARY);
Mat outImage = new Mat();
//圖像腐蝕
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(30,30));
Imgproc.erode(binaryMat, outImage, structImage);
this.saveImage(this.save_dir + "/image_process_erode_threshold.png",outImage);
}
/*
* ------------------------------------------------------------------------------------------------------------
*
* 膨脹
*
* 1. 膨脹說明:
* 圖像的一部分區(qū)域與指定的核進(jìn)行卷積,求核的最`大`值并賦值給指定區(qū)域。
* 膨脹可以理解為圖像中`高亮區(qū)域`的'領(lǐng)域擴(kuò)大'。
* 意思是高亮部分會(huì)侵蝕不是高亮的部分,使高亮部分越來越多。
*
* 2. 膨脹函數(shù)(dilate)
* dilate 有3個(gè)原型方法
*
* dilate(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
* dilate(Mat src, Mat dst, Mat kernel, Point anchor, int iterations)
* dilate(Mat src, Mat dst, Mat kernel)
*
* 參數(shù):
* src : Mat 輸入圖像 對通道數(shù)無要求,但是 depth 必須是 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 之一
* dst : Mat 輸出圖像,與原圖以上的尺寸與類型
* kernel : Mat 膨脹操作的核 , null 時(shí)表示以當(dāng)前像素為中心 3x3 為單位的核
* 一般使用函數(shù) Imgproc.getStructuringElement 來創(chuàng)建核。該函數(shù)會(huì)返回指定形狀或尺寸的矩陣結(jié)構(gòu)元素。
* anchor : Point 瞄點(diǎn)。根據(jù) kernel(核),處理每個(gè)核的某個(gè)點(diǎn)。 (-1,-1)代表取這個(gè)核的中心位置。
* interations : Integer 迭代 dilate(膨脹)的次數(shù),默認(rèn) 1 。。
* borderType : Integer 推斷圖像外部像素的某種邊界模式,一般不需要這個(gè)參數(shù)。
* borderValue : Scalar 當(dāng) borderType 值為常數(shù)時(shí),區(qū)域的顏色一般不用管,
*
* 膨脹,一般不需要borderType,borderValue,均有默認(rèn)值。如果需要使用,可參考官網(wǎng)獲取更多信息
*
* ------------------------------------------------------------------------------------------------------------
*/
/**
* 圖像膨脹處理
* 不做任何處理的圖片
*/
@Test
public void testDilateNomal(){
Mat sourceImage = Imgcodecs.imread(this.p_test_file_path + "/shufa.png");
Mat outImage = new Mat();
//圖像腐蝕
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(30,30));
Imgproc.dilate(sourceImage, outImage, structImage);
this.saveImage(this.save_dir + "/image_process_dilate_nomal.png",outImage);
}
/**
* 圖像膨脹處理
* 灰度處理的圖片
*/
@Test
public void testDilateGray(){
Mat sourceImage = Imgcodecs.imread(this.p_test_file_path + "/shufa-1.jpg",Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
Mat outImage = new Mat();
//圖像腐蝕
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(30,30));
Imgproc.dilate(sourceImage, outImage, structImage);
this.saveImage(this.save_dir + "/image_process_dilate_gray.png",outImage);
}
/**
* 圖像膨脹處理
* 二值化處理的圖片
*/
@Test
public void testDilateThreshold() {
Mat sourceImage = Imgcodecs.imread(this.p_test_file_path + "/shufa.png");
//二值化處理 cv_8uc1 8位單通道格式
Mat binaryMat = new Mat(sourceImage.height(), sourceImage.width(), CvType.CV_8UC1);
Imgproc.threshold(sourceImage, binaryMat,100, 200, Imgproc.THRESH_BINARY);
Mat outImage = new Mat();
//圖像腐蝕
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(30,30));
Imgproc.dilate(binaryMat, outImage, structImage);
this.saveImage(this.save_dir + "/image_process_dilate_threshold.png",outImage);
}
/**
* 查找條形碼案例
*
* 步驟:
* 1. 讀取灰值圖
* 2. 圖像模糊,降噪
* 3. 圖像二值化
* 4. 腐蝕圖像,通過腐蝕過濾掉不是豎線的的區(qū)域
* 5. 膨脹圖像,將腐蝕過的線條數(shù)據(jù)通過膨脹放大
* 6. 繼續(xù)用矩形核膨脹圖像,使線條鏈接成矩形圖像
* 7. 查找輪廓
* 8. 對比所有輪廓,過濾掉寬度小于200,偏斜角<2度的矩形圖像
* 9. 找到圖像并截取
*/
@Test
public void testFindLineCode() {
//讀取灰值圖
Mat sourceImage = Imgcodecs.imread(this.p_test_file_path + "/tiaoma.png",Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
//圖像高斯模糊
Mat gsMat = Mat.ones(sourceImage.size(),sourceImage.type());
Imgproc.GaussianBlur(sourceImage,gsMat,new Size(5,5),0,0);
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-1.png",gsMat);
//圖像二值化,adaptiveThreshold 后面再二值化的專題里講解
Mat thresh_image = Mat.ones(sourceImage.size(),sourceImage.type());
// C 負(fù)數(shù),取反色,超過閾值的為黑色,其他為白色
Imgproc.adaptiveThreshold(gsMat, thresh_image,255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY,7,-2);
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-2.png",thresh_image);
//創(chuàng)建輸出圖像,后續(xù)的操作都是這個(gè)圖像
Mat outImage = new Mat();
/*
* 圖像腐蝕操作
*
* width=2 ,height=20 在腐蝕的時(shí)候,排除大多數(shù)細(xì)的垂直線。
* 這個(gè)參數(shù)不易設(shè)置過大,可以通過多次腐蝕來達(dá)到排除的效果。
*
* ----------------------------------------------------------------------------------
* 注意 width、height 需根據(jù)圖像的大小來設(shè)置。
*
* 比如我這里的示例圖片大小是 1271(width)x648(height)。 我通過比較20是比較理想的值。
* 但是20 并比適用比示例圖小或大的圖像。所以在設(shè)置這個(gè)參數(shù)前,需要根據(jù)圖像大小來調(diào)整。
*
* && 這個(gè)值沒有固定、動(dòng)態(tài)的大小,不要期望自動(dòng)設(shè)置,除非接入 AI 來學(xué)習(xí)。 &&
*
* 但是我們加入到自己工程的業(yè)務(wù)里,我們處理的圖片通常都是固定的幾個(gè)圖像大小
*
* 比如攝像頭獲取圖像,可以指定 500x500
* 比如掃描儀獲取圖像,可以指定 KPI 大小,那么獲取到的同等材質(zhì)(如 A4大小)的數(shù)碼圖片大小也是一樣的。
* 比如數(shù)碼照片,在不同模式下照片大小是一致的,可以根據(jù)圖片信息分類。
*
* 所以,自己根據(jù)自己業(yè)務(wù)經(jīng)常處理的圖片來設(shè)置一個(gè)比例參數(shù) ,通過 sourceImage.heigth()*xParam 來獲取這個(gè)參數(shù)即可。
* ----------------------------------------------------------------------------------
*/
Mat structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(2,20));
Imgproc.erode(thresh_image, outImage, structImage,new Point(-1,-1),3); //腐蝕了3次
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-3.png",outImage);
// 在用腐蝕的圖像,進(jìn)行膨脹,將線條加粗
Imgproc.dilate(outImage, outImage, structImage,new Point(-1,-1),3); // 這里同樣進(jìn)行了3次膨脹
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-4.png",outImage);
/*
* 這里我劃定了一個(gè)10x5 的矩形整列。來將剩余的線條通過膨脹連成區(qū)域。
* 范圍同樣不宜過大或過小。
* 過大:膨脹區(qū)域增大,最終結(jié)果圖像干擾太多
* 過小:膨脹區(qū)域減少,可滿足的條件過多,造成不容易連成一個(gè)整理區(qū)域。
*/
// 再次膨脹,使其連成區(qū)域
structImage = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,5));
Imgproc.dilate(outImage, outImage, structImage,new Point(-1,-1),3);
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-5.png",outImage);
/*
* findContours 找輪廓
*
* 原型方法:
*
* findContours(Mat image, List contours, Mat hierarchy, int mode, int method, Point offset)
*
* image : Mat 是輸入圖像,圖像的格式是8位單通道的圖像,并且被解析為二值圖像(即圖中的所有非零像素之間都是相等的)。
* coutours : List 輸出的輪廓數(shù)組,所有找到的輪廓都會(huì)放在這個(gè)數(shù)組中。MatOfPoint代表這個(gè)對象存儲(chǔ)了輪廓的`點(diǎn)`數(shù)據(jù)
* hierarchy : Mat 這個(gè)參數(shù)可以指定,也可以不指定。
* 如果指定的話,輸出hierarchy,將會(huì)描述輸出輪廓樹的結(jié)構(gòu)信息。
* 0號元素表示下一個(gè)輪廓(同一層級);
* 1號元素表示前一個(gè)輪廓(同一層級);
* 2號元素表示第一個(gè)子輪廓(下一層級);
* 3號元素表示父輪廓(上一層級)
* mode : Integer 輪廓的模式,將會(huì)告訴OpenCV你想用何種方式來對輪廓進(jìn)行提取,有四個(gè)可選的值:
* CV_RETR_EXTERNAL (0):表示只提取最外面的輪廓;
* CV_RETR_LIST (1):表示提取所有輪廓并將其放入列表;
* CV_RETR_CCOMP (2):表示提取所有輪廓并將組織成一個(gè)兩層結(jié)構(gòu),其中頂層輪廓是外部輪廓,第二層輪廓是“洞”的輪廓;
* CV_RETR_TREE (3):表示提取所有輪廓并組織成輪廓嵌套的完整層級結(jié)構(gòu)。
* method : Integer 輪廓如何呈現(xiàn)的方法,有三種可選的方法:
* CV_CHAIN_APPROX_NONE (1):將輪廓中的所有點(diǎn)的編碼轉(zhuǎn)換成點(diǎn);
* CV_CHAIN_APPROX_SIMPLE (2):壓縮水平、垂直和對角直線段,僅保留它們的端點(diǎn);
* CV_CHAIN_APPROX_TC89_L1 (3)or CV_CHAIN_APPROX_TC89_KCOS(4):應(yīng)用Teh-Chin鏈近似算法中的一種風(fēng)格
* offset : Point 可選,如果指定了點(diǎn)偏移,那么返回的輪廓中的所有點(diǎn)均作指定量的偏移
*/
List contours = new ArrayList();
Mat hierarchy = new Mat();
Imgproc.findContours(outImage,contours,hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE,new Point(0,0));
// 根據(jù)輪廓可以找到的形狀數(shù)組
// Rect[] boundRect = new Rect[contours.size()];
// 循環(huán)找到的所有輪廓
for(int i = 0; i < contours.size();i++) {
//將輪廓保存為區(qū)域
// boundRect[i] = Imgproc.boundingRect(contours.get(i));
// System.out.println(boundRect[i].tl());
// System.out.println(boundRect[i].br());
// 獲取輪廓內(nèi),最小外包矩形
RotatedRect min = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(i).toArray()));
//偏轉(zhuǎn)角度
if(min.angle < 2){
//獲取一個(gè)矩形
Rect minRect = min.boundingRect();
//將寬度<200的排除
if( ( minRect.br().x - minRect.tl().x ) > 200 ){
//截取
Mat code = sourceImage.submat(minRect);
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-code-"+i+".png",code);
}
//在原圖上把該矩形表示出來
Imgproc.rectangle(sourceImage, minRect.tl(), minRect.br(), new Scalar(0, 255, 0), 1, Imgproc.LINE_AA, 0);
}
}
//輸出原圖
this.saveImage(this.save_dir + "/image_process_dilate_tiaoma-6.png",sourceImage);
}
}
部分結(jié)果展示
膨脹 dilate
原圖:
膨脹后:
腐蝕 erode
獲取條形碼
獲取條形碼的效果可能不是最好,方法也不是最好的,只是我學(xué)到這里的一些積累。只是拋出一種方法而已。
廣告欄: 歡迎關(guān)注我的 個(gè)人博客
總結(jié)
以上是生活随笔為你收集整理的图像腐蚀 java_OpenCV3 图像膨胀 dilate、腐蚀 erode、提取图像中的条形码 JAVA 实现...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 大于30分钟,如何将会话超时设
- 下一篇: java炒黄金_炒黄金追单的一些问题分析