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); } }
