目录
一、多通道的分离与合并
1)多通道图像的分离
基本概念:
多通道分离是指将彩色图像的各个颜色通道分离成独立的图像。对于一个标准的BGR(或RGB)图像,这意味着将图像分解为蓝色(B)、绿色(G)和红色(R)三个单通道灰度图像。
意义和作用:
- 灵活性:通过分离通道,可以单独处理每个颜色通道的信息,这为图像处理提供了更大的灵活性。例如,如果只关心图像中的红色信息,可以只处理红色通道。
- 内存管理:在处理大型图像时,分离通道可以减少数据所占据的内存,因为每个通道都是独立的灰度图像,相对于原始彩色图像来说,数据量更小。
- 性能优化:针对特定通道进行处理可以加快程序的运行速度,因为处理的数据量减少了。
- 特定任务需求:在某些图像处理任务中,如颜色空间转换、滤波器处理等,需要单独处理每个通道。
使用Core.split()
方法可以将一个多通道图像分离成多个单通道图像。
// 假设你已经有一个Bitmap对象bitmap,它包含了要处理的图像
Mat srcMat = new Mat();
Utils.bitmapToMat(bitmap, srcMat);
List<Mat> channels = new ArrayList<>(3);
Core.split(srcMat, channels);
Mat blueChannel = channels.get(0); // 蓝色通道
Mat greenChannel = channels.get(1); // 绿色通道
Mat redChannel = channels.get(2); // 红色通道
2)多通道图像的合并
基本概念:
多通道合并是将多个单独的图像(通常是之前分离出来的颜色通道)重新组合成一个多通道图像。这个过程是通道分离的逆操作。
意义和作用:
- 图像重建:在修改了单个或多个通道之后,需要重新构建原始图像或生成新的彩色图像。多通道合并是实现这一目标的关键步骤。
- 保持图像完整性:通过合并通道,可以确保图像的完整性和一致性。如果分离后的通道在处理过程中发生了变化,合并后的图像将反映这些变化。
- 后续处理的基础:在某些图像处理流程中,多通道合并是后续处理步骤的基础。例如,在进行颜色空间转换后,可能需要将转换后的通道合并回一个彩色图像以进行进一步的分析或显示。
使用Core.merge()
方法可以将多个单通道图像合并成一个多通道图像。
// 创建一个存储合并后图像的Mat对象
Mat mergedMat = new Mat();
// 将分离后的通道合并回一个多通道图像
List<Mat> channelsToMerge = new ArrayList<>(3);
channelsToMerge.add(blueChannel);
channelsToMerge.add(greenChannel);
channelsToMerge.add(redChannel);
Core.merge(channelsToMerge, mergedMat);
// 将合并后的图像转换回Bitmap对象以进行显示或其他处理
Bitmap resultBitmap = Bitmap.createBitmap(mergedMat.cols(), mergedMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mergedMat, resultBitmap);
二、图像二值化
图像二值化是一种将彩色或灰度图像转换为只有黑色和白色两种像素值的图像处理技术。这种处理方法能有效提取图像中的目标物体,将背景及噪声区分开来,为后续的图像分析、物体识别和文字识别等提供便利。
其核心思想是设定一个阈值,将图像中的像素值根据该阈值分为两类:大于阈值的像素点设置为白色(或黑色),小于阈值的像素点设置为黑色(或白色)。通过调整阈值,可以控制二值化后图像中前景和背景的分割效果。
1)全局阈值化
全局阈值化是指在整个图像中使用一个固定的阈值进行二值化处理。这种方法适用于图像中前景和背景的灰度值差异明显的场景。在OpenCV中,可以使用threshold方法实现全局阈值化。
// 创建存储二值化结果的Mat对象
Mat dstMat = new Mat();
// 全局阈值化处理,使用大津法自动确定阈值
double thresh = Imgproc.threshold(srcMat, dstMat, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
// 打印大津法确定的阈值
System.out.println("OTSU阈值: " + thresh);
ps:THRESH_BINARY | THRESH_OTSU
参数表示使用大津法自动确定阈值。
数学上还有个常用的三角形法,取直方图两谷一顶点使三角形面积最大。相比大律法各有优劣,但 OpenCV标准方法里没实现,可自行实现。
2)局部阈值化
局部阈值化是指根据图像中不同区域的灰度值差异,使用不同的阈值进行二值化处理。这种方法适用于图像中不同区域亮度差异较大的场景。在OpenCV中,可以使用adaptiveThreshold方法实现局部阈值化。
// 创建存储二值化结果的Mat对象
Mat dstMat = new Mat();
// 局部阈值化处理,使用自适应阈值算法
Imgproc.adaptiveThreshold(srcMat, dstMat, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
Imgproc.THRESH_BINARY, 11, 2);
ps:ADAPTIVE_THRESH_GAUSSIAN_C
参数表示使用高斯加权和算法计算局部阈值。
11
表示用于计算阈值的邻域大小(11x11)。
2
表示从计算出的平均值或加权平均值中减去的常数。
3)图像二值化的应用
- 文档扫描与OCR:在文档扫描和OCR(光学字符识别)技术中,图像二值化是一个关键步骤。通过二值化处理,可以将文档中的文字与背景分离开来,从而提高OCR的识别准确率。
- 车牌识别:在车牌识别系统中,图像二值化也被广泛应用。通过对车牌图像进行二值化处理,可以提取出车牌的轮廓和字符信息,进而实现车牌的自动识别。
- 图像处理与分析:在图像处理和分析领域,图像二值化常用于图像分割、特征提取等任务。通过二值化处理,可以将图像中的感兴趣区域(ROI)与背景分离开来,为后续的分析和处理提供便利。
三、LUT查找表
1)概念和原理
LUT(Look-Up Table,查找表)函数是OpenCV中一个非常重要的工具,它允许用户通过预定义的映射关系快速修改图像中像素的值,而无需对每个像素进行复杂的计算。LUT函数通过一个预定义的查找表(通常是一个一维数组),将输入图像中的每个像素值映射为新的像素值。这种映射关系可以是一对一的,也可以是多对一的,具体取决于查找表的内容。
在图像处理中,LUT查找表可以作为像素灰度值的映射表,以像素灰度值作为索引,以灰度值映射后的数值作为表中的内容。这种映射关系可以应用于图像的灰度级变换、颜色空间转换、图像增强等场景。
2)OpenCV中LUT查找表操作的API使用方法
在Android OpenCV中,LUT查找表操作的API是public static void LUT(Mat src, Mat lut, Mat dst)
。该函数的参数解释如下:
src
:输入图像矩阵,其数据类型只能是CV_8U
(即8位无符号整型)。lut
:256个像素灰度值的查找表,单通道或者与src
通道数相同。查找表的数据类型和通道数应与输入图像相匹配或兼容。dst
:输出图像矩阵,其尺寸与src
相同,数据类型与lut
相同。
若lut
参数为单通道,则输入变量src
中的每个通道都按照一个LUT查找表进行映射。如果lut
参数是多通道,则输入变量src
中的第i个通道按照lut
参数的第i个通道LUT查找表进行映射。函数输出图像的数据类型不与原图像的数据类型保持一致,而是和LUT查找表的数据类型保持一致。
示例:
// 读取输入图像(假设为灰度图像)
Mat src = Imgproc.imread("input.jpg", Imgproc.IMREAD_GRAYSCALE);
if (src.empty()) {
// 处理图像读取失败的情况
return;
}
// 准备查找表
byte[] lut = new byte[256];
for (int i = 0; i < 256; i++) {
lut[i] = (byte) (i < 128 ? 0 : 255);
}
Mat lutMat = new Mat(1, 256, CvType.CV_8U);
lutMat.put(0, 0, lut);
// 创建输出图像(无需显式创建,OpenCV会在LUT函数调用时自动创建)
Mat dst = new Mat();
// 调用LUT函数进行像素值映射
Imgproc.LUT(src, lutMat, dst);
// 显示或保存结果(此处省略显示或保存代码,可根据需要添加)
3)实际应用价值
-
图像处理:
- 色彩空间转换:LUT在色彩空间转换中起到了至关重要的作用,如将RGB色彩空间转换到CMYK色彩空间。通过预计算和存储一系列色彩转换结果,LUT能够加速色彩转换过程,减少计算时间,提高处理效率。
- 色调映射:LUT常用于色调映射中,根据图像中颜色的亮度或灰度值重新分布色彩,以增强对比度或保留更多的图像细节。例如,在HDR(高动态范围)图像中,使用LUT可以将亮度范围压缩到一个显示器能显示的范围内。
- 图像增强:LUT还可以用于图像的对比度增强、亮度调整等操作,通过定义合适的映射关系,增强图像的视觉效果。
-
视频处理:
- 色彩校正和调色:LUT是视频剪辑和照片后期处理中常用的工具,用于快速改变视频或图片的色调、对比度和氛围。它可以将一种颜色映射到另一种颜色,实现色彩校正和赋予视频特定的电影感。
- 多机位拍摄色彩统一:在多机位拍摄时,不同设备的颜色可能会有所不同,使用LUT可以让所有镜头的色彩更加统一。
-
摄影:
- LUT预设:LUT预设是一组预先配置好的LUT文件,设计用于快速应用特定的色彩效果。摄影师可以使用这些预设迅速为他们的图像或视频添加特定的风格,如复古、冷色调或暖色调。
- 视觉增强:通过应用LUT预设,摄影师可以增强图像的清晰度、对比度或饱和度,为作品增添独特的视觉效果。
-
印刷:
- 色彩管理:LUT在印刷领域也扮演着重要角色,它可以帮助将图像从一种色彩空间转换到另一种色彩空间,以适应不同的打印设备和介质。
- 预览效果:使用LUT,印刷师可以在打印之前预览图像在目标设备上的效果,从而确保最终的打印质量与预期相符。
-
颜色校正:
- 校正色偏:LUT可用于校正图像或视频中的色偏,使颜色更加自然。例如,调整白平衡、修复曝光问题等。
- Gamma校正:LUT还可以用于实现Gamma校正,调整图像的亮度级别,使图像看起来更加平衡和自然。
四、图像透视变换、图像仿射变换与极坐标变换
1)原理
1.透视变换(Perspective Transformation)是指将图像投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。它是一种非线性变换,可以将一个二维坐标系中的点映射到三维坐标系中的点,然后再将其投影到另一个二维坐标系中的点。这种变换可以改变图像中的形状,并模拟真实世界中的透视效果。
透视变换的原理基于透视投影的几何原理,它利用四个对应点(原图坐标+目标坐标)之间的映射关系来变换图像。通过计算一个3x3的透视变换矩阵,可以将原图像中的任意点映射到目标图像中的对应点,从而实现图像的透视变换。
2.仿射变换(Affine Transformation)是一种二维坐标到二维坐标之间的线性变换,它可以保持图像的“直线性和平行性”。也就是说,经过仿射变换后的图像,原图像中的直线仍然保持为直线,且平行线仍然保持平行。
仿射变换可以通过一个2x3的变换矩阵来表示,该矩阵包含了六个参数,分别对应图像的平移、旋转、缩放和倾斜等变换。通过计算变换矩阵,可以将原图像中的任意点映射到目标图像中的对应点,从而实现图像的仿射变换。
3.极坐标变换是一种将图像从直角坐标系(也称为笛卡尔坐标系)转换到极坐标系的技术。在直角坐标系中,图像上的每个点由其横坐标(x)和纵坐标(y)表示;而在极坐标系中,每个点则由其距离原点(即极径)和与x轴正方向的角度(即极角)表示。
极坐标变换的意义在于,它能够将一些在直角坐标系中难以处理的图像问题转化为在极坐标系中更容易处理的问题。例如,对于圆形或环形图像(如钟表、圆盘等),极坐标变换可以将其变换为矩形图像,从而方便后续的图像处理和分析。
这里引用知乎上一位研究自动驾驶算法的博主笔记https://zhuanlan.zhihu.com/p/681916781
关于极坐标变换引用另一博客[OpenCV实战]51 基于OpenCV实现图像极坐标变换与逆变换_opencv坐标系转换-优快云博客
2)示例
1.
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import android.graphics.Bitmap;
public class PerspectiveTransform {
public static Bitmap perspectiveTransform(Bitmap sourceBitmap, Point[] srcPoints, Point[] dstPoints) {
Mat sourceMat = new Mat();
Bitmap bitmap32 = sourceBitmap.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bitmap32, sourceMat);
Imgproc.cvtColor(sourceMat, sourceMat, Imgproc.COLOR_RGBA2BGR);
Mat dstMat = new Mat();
Mat transform = Imgproc.getPerspectiveTransform(new MatOfPoint2f(srcPoints), new MatOfPoint2f(dstPoints));
Imgproc.warpPerspective(sourceMat, dstMat, transform, new Size(sourceBitmap.getWidth(), sourceBitmap.getHeight()));
Bitmap resultBitmap = Bitmap.createBitmap(dstMat.cols(), dstMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dstMat, resultBitmap);
return resultBitmap;
}
}
调用
Point[] srcPoints = {
new Point(100, 100),
new Point(200, 100),
new Point(200, 200),
new Point(100, 200)
};
Point[] dstPoints = {
new Point(0, 0),
new Point(200, 0),
new Point(200, 300),
new Point(0, 300)
};
Bitmap transformedBitmap = PerspectiveTransform.perspectiveTransform(sourceBitmap, srcPoints, dstPoints);
2.
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import android.graphics.Bitmap;
public class AffineTransform {
public static Bitmap affineTransform(Bitmap sourceBitmap, Point[] srcPoints, Point[] dstPoints) {
Mat sourceMat = new Mat();
Bitmap bitmap32 = sourceBitmap.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bitmap32, sourceMat);
Imgproc.cvtColor(sourceMat, sourceMat, Imgproc.COLOR_RGBA2BGR);
Mat transform = Imgproc.getAffineTransform(new MatOfPoint2f(srcPoints), new MatOfPoint2f(dstPoints));
Mat dstMat = new Mat();
Imgproc.warpAffine(sourceMat, dstMat, transform, new Size(sourceBitmap.getWidth(), sourceBitmap.getHeight()));
Bitmap resultBitmap = Bitmap.createBitmap(dstMat.cols(), dstMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dstMat, resultBitmap);
return resultBitmap;
}
}
调用
Point[] srcPoints = {
new Point(0, 0),
new Point(sourceBitmap.getWidth(), 0),
new Point(0, sourceBitmap.getHeight())
};
Point[] dstPoints = {
new Point(0, 0),
new Point(sourceBitmap.getWidth() * 2, 0),
new Point(0, sourceBitmap.getHeight() / 2)
};
Bitmap transformedBitmap = AffineTransform.affineTransform(sourceBitmap, srcPoints, dstPoints);
3.
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import android.graphics.Bitmap;
public class PolarTransform {
public static Bitmap polarTransform(Bitmap sourceBitmap, Point center, double maxRadius) {
Mat sourceMat = new Mat();
Bitmap bitmap32 = sourceBitmap.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bitmap32, sourceMat);
Imgproc.cvtColor(sourceMat, sourceMat, Imgproc.COLOR_RGBA2BGR);
Mat dstMat = new Mat();
Imgproc.warpPolar(sourceMat, dstMat, new Size(sourceMat.cols(), sourceMat.rows()), center, maxRadius, Imgproc.INTER_LINEAR + Imgproc.WARP_FILL_OUTLIERS);
Bitmap resultBitmap = Bitmap.createBitmap(dstMat.cols(), dstMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dstMat, resultBitmap);
return resultBitmap;
}
}
调用
Point center = new Point(sourceBitmap.getWidth() / 2, sourceBitmap.getHeight() / 2);
double maxRadius = Math.sqrt(Math.pow(sourceBitmap.getWidth() / 2, 2) + Math.pow(sourceBitmap.getHeight() / 2, 2));
Bitmap transformedBitmap = PolarTransform.polarTransform(sourceBitmap, center, maxRadius);
3)实际应用价值
1.
图像校正:透视变换可以用于校正因拍摄角度或镜头畸变导致的图像倾斜或拉伸,如文档扫描校正、车牌识别中的车牌区域校正等。
视角转换:通过透视变换,可以实现图像的视角转换,使其看起来更具吸引力或符合特定的视觉需求,如增强现实(AR)中的虚拟物体叠加、虚拟背景替换等。
图像增强:透视变换还可以用于调整图像的视角,突出图像中的某些特征或细节,从而增强图像的视觉效果。
2.仿射与透视功能基本相近,可以说仿射其实就是二维平面上的透视
图像拼接:在图像拼接任务中,仿射变换可以用于将多张图像对齐并拼接成一个完整的图像。
3.
钟表图像处理:对于钟表图像,极坐标变换可以将其表盘部分变换为矩形图像,从而方便对表盘上的刻度、指针等特征进行识别和检测。
圆盘图像处理:在处理圆盘类图像(如CD、DVD等)时,极坐标变换可以将其变换为矩形图像,从而方便对圆盘上的文字、图案等特征进行提取和分析。
虹膜识别算法