Skip to content
鼓励作者:欢迎打赏犒劳

图像轮廓

二值化(阈值化)

在 OpenCV 中,图像二值化通过 cv2.threshold() 函数实现,该函数将灰度图像转换为二值图像(只有 0 和 255 两种像素值)。以下是详细说明:

java
public static double threshold(
    Mat src, 
    Mat dst, 
    double thresh, 
    double maxval, 
    int type
)

参数说明

参数名类型说明
srcMat输入图像:必须是单通道灰度图像(8位或32位浮点型)
dstMat输出图像:与输入图像相同尺寸和类型的二值化结果
threshdouble阈值:用于分类像素的阈值值(0-255之间)
maxvaldouble最大值:当像素值超过阈值时赋予的值(通常设为255)
typeint阈值类型:决定如何应用阈值(使用OpenCV常量指定)

返回值

返回值类型说明
retvaldouble实际使用的阈值值(在使用自动阈值方法时特别有用)

阈值类型常量(type参数)

基础阈值类型

常量名(Java)公式效果说明
THRESH_BINARY0dst(x,y) = (src(x,y) > thresh) ? maxval : 0大于阈值设为maxval,否则设为0
THRESH_BINARY_INV1dst(x,y) = (src(x,y) > thresh) ? 0 : maxval大于阈值设为0,否则设为maxval
THRESH_TRUNC2dst(x,y) = (src(x,y) > thresh) ? thresh : src(x,y)大于阈值设为阈值,否则保持不变
THRESH_TOZERO3dst(x,y) = (src(x,y) > thresh) ? src(x,y) : 0大于阈值保持不变,否则设为0
THRESH_TOZERO_INV4dst(x,y) = (src(x,y) > thresh) ? 0 : src(x,y)大于阈值设为0,否则保持不变

自动阈值类型(需与基础类型组合使用)

常量名(Java)说明
THRESH_OTSU8使用Otsu算法自动计算最佳阈值(适用于双峰直方图图像)
THRESH_TRIANGLE16使用Triangle算法自动计算阈值(适用于单峰直方图图像)

组合使用示例

java
int otsuType = THRESH_BINARY + THRESH_OTSU;
int triangleType = THRESH_BINARY + THRESH_TRIANGLE;

示例

java
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
	 
public class Threshold {
	 
	public static void main(String[] args) {
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);       
		
		//读取图像并在屏幕上显示
		Mat src=Imgcodecs.imread("C:\\Users\\Think\\Desktop\\TestCV\\church.png",Imgcodecs.IMREAD_GRAYSCALE);
		HighGui.imshow("src", src); 
		HighGui.waitKey(0);         
	 	Mat dst=new Mat();

		//二值化处理并在屏幕上显示,阈值=90
	 	Imgproc.threshold(src, dst, 90, 255, Imgproc.THRESH_BINARY);   
		HighGui.imshow("threshold=90", dst); 
		HighGui.waitKey(0); 

		//二值化处理并在屏幕上显示,阈值=120
	 	Imgproc.threshold(src, dst, 120, 255, Imgproc.THRESH_BINARY);   
		HighGui.imshow("threshold=120", dst); 
		HighGui.waitKey(0); 

		//二值化处理并在屏幕上显示,阈值=180
	 	Imgproc.threshold(src, dst, 180, 255, Imgproc.THRESH_BINARY);   
		HighGui.imshow("threshold=180", dst); 
		HighGui.waitKey(0); 	
		System.exit(0);
		
	}
}

Otsu自动阈值处理

java
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
	 
public class Threshold {
	 
	public static void main(String[] args) {
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);       
		//读取图像并在屏幕上显示
		Mat src = Imgcodecs.imread("C:\\Users\\Think\\Desktop\\TestCV\\church.png", Imgcodecs.IMREAD_GRAYSCALE);
		Mat dst = new Mat();

		// 应用Otsu自动阈值
		double otsuThreshold = Imgproc.threshold(
				src,
				dst,
				0, // thresh参数被忽略
				255,
				Imgproc.THRESH_BINARY + Imgproc.THRESH_OTSU
		);

		System.out.println("Otsu计算的最佳阈值: " + otsuThreshold);
		HighGui.imshow("otsu_output.jpg", dst);
		HighGui.waitKey(0);
		System.exit(0);
		
	}
	 
}

注意事项

  1. 输入图像要求
    • 必须是单通道灰度图像
    • 使用Imgproc.cvtColor()转换彩色图像为灰度图:
      java
      Mat gray = new Mat();
      Imgproc.cvtColor(colorImage, gray, Imgproc.COLOR_BGR2GRAY);

查找&绘制轮廓

java
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;

/**
 * 公众号:干货食堂
 */
public class Test {

    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        //读取图像,使用灰度模式
        Mat src=Imgcodecs.imread("C:\\Users\\Think\\Desktop\\TestCV\\palm.png",Imgcodecs.IMREAD_GRAYSCALE);

        //进行阚值化操作,将图像转换为二值图像
        Mat thresh = new Mat();
        Imgproc.threshold(src, thresh, 128, 255, Imgproc.THRESH_BINARY);
        //存储轮廓的容器
        ArrayList<MatOfPoint> contours = new ArrayList<>();
        //存储轮廓的层次结构(可选)
        Mat hierarchy = new Mat();

        //查找轮廓
        Imgproc.findContours(thresh, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
        //在原图上绘制轮廓
        Mat dst = Mat.zeros(src.size(), CvType.CV_8UC3); // 创建一个空白的彩色图像
        Imgproc.drawContours(dst, contours, -1, new Scalar(0, 255, 0), 2);

        HighGui.imshow("轮廓", dst);
        HighGui.waitKey(0);
        HighGui.destroyAllWindows();
    }
}

如有转载或 CV 的请标注本站原文地址