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