Java 版本: JavaCV
用OpenCV读一张图片并显示。只需将程序运行时的截图回复。如何安装配置创建项目编写OpenCV代码,可参考何东健课件和源代码或其他资源。
1. 用OpenCV读一张图片,显示该图的直方图。只需截图回复。如何安装配置创建项目编写OpenCV代码,可参考何东健课件和源代码的第3章或其他资源。
2. 用OpenCV读一张图片,求该图的离散傅立叶变换,并显示其频谱。只需截图回复。如何安装配置创建项目编写OpenCV代码,可参考何东健课件和源代码的第5章或其他资源。
3. 虽然我们是以OpenCV来布置实践,但是如果同学们采用其他方式,也是可以的,比如使用Matlab等等。只要能把问题解决。不同的途径有不同的特点,在实践过程中同学们可以去体会。
4. 对第3章理论内容,只要求同学们了解会用即可,如果想进一步了解相关内容,同学们可以参考数字信号处理相关书籍或者其他数字图像处理书籍。
直方图
/**
* @program: learn-opencv
* @description: 绘制图片直方图
* @author: Mr.Dai
* @create: 2020-03-03 16:30
**/
public class Histogram {
private final static String path=System.getProperty("user.dir")+"\\catton.jpg";
static{
platformUtils.loadLibraries();
}
public static void main(String[] args) {
Mat imread = Imgcodecs.imread(path);
HighGui.imshow(" 原图像",imread);
plotGrayHistogram(imread);
// 无限等待按键按下
HighGui.waitKey(0);
}
public static void plotGrayHistogram(Mat img) {
java.util.List<Mat> images = new ArrayList<>();
images.add(img);
MatOfInt channels = new MatOfInt(0); // 图像通道数,0表示只有一个通道
MatOfInt histSize = new MatOfInt(256); // CV_8U类型的图片范围是0~255,共有256个灰度级
Mat histogramOfGray = new Mat(); // 输出直方图结果,共有256行,行数的相当于对应灰度值,每一行的值相当于该灰度值所占比例
MatOfFloat histRange = new MatOfFloat(0, 255);
Imgproc.calcHist(images, channels, new Mat(), histogramOfGray, histSize, histRange, false); // 计算直方图
// 按行归一化
Core.normalize(histogramOfGray, histogramOfGray, 0, histogramOfGray.rows(), Core.NORM_MINMAX, -1, new Mat());
// 创建画布
int histImgRows = 300;
int histImgCols = 300;
int colStep = (int) Math.floor(histImgCols / histSize.get(0, 0)[0]);
Mat histImg = new Mat(histImgRows, histImgCols, CvType.CV_8UC3, new Scalar(255,255,255)); // 重新建一张图片,绘制直方图
for (int i = 0; i < histSize.get(0, 0)[0]; i++) { // 画出每一个灰度级分量的比例,注意OpenCV将Mat最左上角的点作为坐标原点
Imgproc.line(histImg,
new org.opencv.core.Point(colStep * i, histImgRows - 20),
new org.opencv.core.Point(colStep * i, histImgRows - Math.round(histogramOfGray.get(i, 0)[0]) - 20),
new Scalar(0, 0,0), 2,8,0);
if (i%50 == 0) {
Imgproc.putText(histImg, Integer.toString(i), new org.opencv.core.Point(colStep * i, histImgRows - 5), 1, 1, new Scalar(0, 0, 0)); // 附上x轴刻度
}
}
//显示出来 对namedWindos 与cv::imshow 封装
HighGui.imshow("Gray Histogram",histImg);
}
}傅里叶:
/**
* @Description: 傅里叶变换
* @Author: Dai.GuoWei
* @Date: 2020/3/3
*/
public class TestDft {
public Mat dftStart(Mat img) {
img.convertTo(img, CvType.CV_32FC1);
System.out.println("img类型: " + img.type() + " " + img.channels());
int M = Core.getOptimalDFTSize(img.rows()); // 获得最佳DFT尺寸,为2的次方
int N = Core.getOptimalDFTSize(img.cols()); // 同上
Mat padded = new Mat();
System.out.println("padded 类型: " + padded.size() + " " + padded.type() + " " + padded.channels());
Core.copyMakeBorder(img, padded, 0, M - img.rows(), 0, N - img.cols(), Core.BORDER_CONSTANT, new Scalar(0)); // opencv中的边界扩展函数,提供多种方式扩展
System.out.println("padded 类型: " + padded.size() + " " + padded.type() + " " + padded.channels());
System.out.println("padded 类型: " + padded.size() + " " + padded.type() + " " + padded.channels());
List<Mat> planes = new ArrayList<Mat>(); // Mat 数组,第一个为扩展后的图像,一个为空图像,
planes.add(padded);
planes.add(Mat.zeros(padded.size(), CvType.CV_32FC1));
Mat complexImg = new Mat();
System.out
.println("complexImg 类型: " + complexImg.size() + " " + complexImg.type() + " " + complexImg.channels());
Core.merge(planes, complexImg); // 合并成一个Mat
System.out
.println("complexImg 类型: " + complexImg.size() + " " + complexImg.type() + " " + complexImg.channels());
Core.dft(complexImg, complexImg); // FFT变换, dft需要一个2通道的Mat
// compute log(1 + sqrt(Re(DFT(img))**2 + Im(DFT(img))**2))
Core.split(complexImg, planes); // 分离通道, planes[0] 为实数部分,planes[1]为虚数部分
Core.magnitude(planes.get(0), planes.get(1), planes.get(0)); // 求模
Mat mag = planes.get(0);
Core.add(mag, new Scalar(1), mag);
// mag += new Scalar(1);
Core.log(mag, mag); // 模的对数
// crop the spectrum, if it has an odd number of rows or columns
mag = new Mat(mag, new Rect(0, 0, mag.cols() & -2, mag.rows() & -2)); // 保证偶数的边长
int cx = mag.cols() / 2;
int cy = mag.rows() / 2;
// rearrange the quadrants of Fourier image //对傅立叶变换的图像进行重排,4个区块,从左到右,从上到下
// 分别为q0, q1, q2, q3
// so that the origin is at the image center // 对调q0和q3, q1和q2
Mat tmp = new Mat();
Mat q0 = new Mat(mag, new Rect(0, 0, cx, cy));
Mat q1 = new Mat(mag, new Rect(cx, 0, cx, cy));
Mat q2 = new Mat(mag, new Rect(0, cy, cx, cy));
Mat q3 = new Mat(mag, new Rect(cx, cy, cx, cy));
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
// Core.normalize(mag, mag, 0, 255, Core.NORM_MINMAX); // 规范化值到 0~1 显示图片的需要 归一化
Core.normalize(mag,mag, 0, 255, Core.NORM_MINMAX,CvType.CV_8UC1,new Mat());
System.out.println("mag 类型: " + mag.size() + " " + mag.type() + " " + mag.channels());
mag.convertTo(mag, CvType.CV_8U);
return mag;
}
private final static String path=System.getProperty("user.dir")+"\\catton.jpg";
static{
platformUtils.loadLibraries();
}
public static void main(String[] args) {
Mat img = Imgcodecs.imread(path);
Mat gray = new Mat();
Imgproc.cvtColor(img, gray, Imgproc.COLOR_RGB2GRAY);
TestDft t = new TestDft();
Mat dst = t.dftStart(gray);
HighGui.imshow("原图", img);
HighGui.imshow("dft效果图", dst);
HighGui.waitKey(0);
HighGui.destroyAllWindows();
System.exit(0);
}
}
来源:https://www.cnblogs.com/dgwblog/p/12403307.html
