
图像轮廓
二值化(阈值化)
在 OpenCV 中,图像二值化通过 cv2.threshold() 函数实现,该函数将灰度图像转换为二值图像(只有 0 和 255 两种像素值)。以下是详细说明:
java
public static double threshold(
Mat src,
Mat dst,
double thresh,
double maxval,
int type
)
参数说明
参数名 | 类型 | 说明 |
---|---|---|
src | Mat | 输入图像:必须是单通道灰度图像(8位或32位浮点型) |
dst | Mat | 输出图像:与输入图像相同尺寸和类型的二值化结果 |
thresh | double | 阈值:用于分类像素的阈值值(0-255之间) |
maxval | double | 最大值:当像素值超过阈值时赋予的值(通常设为255) |
type | int | 阈值类型:决定如何应用阈值(使用OpenCV常量指定) |
返回值
返回值 | 类型 | 说明 |
---|---|---|
retval | double | 实际使用的阈值值(在使用自动阈值方法时特别有用) |
阈值类型常量(type参数)
基础阈值类型
常量名(Java) | 值 | 公式 | 效果说明 |
---|---|---|---|
THRESH_BINARY | 0 | dst(x,y) = (src(x,y) > thresh) ? maxval : 0 | 大于阈值设为maxval,否则设为0 |
THRESH_BINARY_INV | 1 | dst(x,y) = (src(x,y) > thresh) ? 0 : maxval | 大于阈值设为0,否则设为maxval |
THRESH_TRUNC | 2 | dst(x,y) = (src(x,y) > thresh) ? thresh : src(x,y) | 大于阈值设为阈值,否则保持不变 |
THRESH_TOZERO | 3 | dst(x,y) = (src(x,y) > thresh) ? src(x,y) : 0 | 大于阈值保持不变,否则设为0 |
THRESH_TOZERO_INV | 4 | dst(x,y) = (src(x,y) > thresh) ? 0 : src(x,y) | 大于阈值设为0,否则保持不变 |
自动阈值类型(需与基础类型组合使用)
常量名(Java) | 值 | 说明 |
---|---|---|
THRESH_OTSU | 8 | 使用Otsu算法自动计算最佳阈值(适用于双峰直方图图像) |
THRESH_TRIANGLE | 16 | 使用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);
}
}
注意事项
- 输入图像要求:
- 必须是单通道灰度图像
- 使用
Imgproc.cvtColor()
转换彩色图像为灰度图:javaMat 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();
}
}