如上4張圖檔,其中 2 3 是向左凸出來的。
圖檔處理,以上圖2為例, 圖檔 -> 高斯模糊
-> 圖檔灰階化處理
-> 邊緣檢測
,沒有二值化處理。
最後的圖檔,在python下,顯示的像素點
思路,統計每個 x 軸(因為我是檢測圖檔是否向左凸出來)上,rgb 等于255的個數。假設圖檔是像左凸出來的,那麼前幾個(自定義)坐标上的統計值,一定是小于最大統計值的,這裡定義小于 最大值的1/3。
簡單代碼如下:
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.springframework.util.CollectionUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
public class CheckLeftOut {
public static void main(String[] args) {
// 這個必須要寫,不寫報java.lang.UnsatisfiedLinkError
System.load("D:\\java_project\\common\\lib\\opencv_java440_x64.dll"); //絕對路徑
String name = "1600853293536"; //1600853293536 1600852044392 判斷小滑塊是否左凸出來 {11=3, 12=9, 13=6, 14=4, 15=4, 16=4, 17=2, 18=4, 19=2, 20=2} {11=6, 12=6, 13=6, 14=4, 15=4, 16=4, 17=2, 18=4}
String small = "C:\\generate_captcha\\" + name + ".png";
System.out.println(imageOut(small));
}
public static boolean imageOut(String path) {
// 這個必須要寫,不寫報java.lang.UnsatisfiedLinkError
System.load("D:\\java_project\\common\\lib\\opencv_java440_x64.dll"); //絕對路徑
Mat src = imread(path);
Mat result = Dis3.gaussianBlur(src);
//Imgcodecs.imwrite("C:\\generate_captcha\\b1_1.png", result);
result = gray(result);
//Imgcodecs.imwrite("C:\\generate_captcha\\b1_2.png", result);
//可以不需要
//result = binary(result);
//Imgcodecs.imwrite("C:\\generate_captcha\\b1_3.jpg", result);
result = canny(result);
//Imgcodecs.imwrite("C:\\generate_captcha\\b1_4.png", result);
//System.out.println(getImageGRB("C:\\generate_captcha\\b1_4.png"));
Map<Integer, Integer> map = getImageGRB(mat2InputStream(getExtensionName(path), result));
if(CollectionUtils.isEmpty(map)) {
return false;
}
return imageOut(map);
}
/**
*
* @param map, key 是橫坐标,value 是橫坐标像素點大于0的統計
* 首先算出像素點最大的值,如果圖檔的缺口是凸出來的,前幾個橫坐标(前5個,自己定義)的統計值肯定是小于最大值(一般不超過1/3,自己定義)
* @return
*/
public static boolean imageOut(Map<Integer, Integer> map) {
List<Integer> xList = new ArrayList<>(); //橫坐标
List<Integer> yList = new ArrayList<>(); //橫坐标像素點大于0的統計
map.forEach((k, v) -> {
xList.add(k);
yList.add(v);
});
int max = yList.stream().mapToInt(v -> v).max().orElse(0);
max = max / 3;
int size = xList.size() > 5 ? 5 : xList.size();
for(int i = 0; i < size; i ++) {
if(map.get(xList.get(i)) >= max) {
return false;
}
}
return true;
}
/***
* 擷取擴充名,不包含 .
* @param file
* @return
*/
public static String getExtensionName(String file) {
int index = file.lastIndexOf(".");
return file.substring(index + ".".length(), file.length());
}
/***
* @param extensionName:檔案擴充名,不包含 .
* @param mat
* @return
*/
public static InputStream mat2InputStream(String extensionName, Mat mat)
{
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode("." + extensionName, mat, mob);
byte[] byteArray = mob.toArray();
return new ByteArrayInputStream(byteArray);
}
/**
* 傳回 map, key 是橫坐标,value 是橫坐标像素點大于0的統計
* @param inputStream
* @return
*/
public static Map<Integer, Integer> getImageGRB(InputStream inputStream) {
Map<Integer, Integer> map = new LinkedHashMap<>();
try {
BufferedImage bufImg = ImageIO.read(inputStream);
int height = bufImg.getHeight();
int width = bufImg.getWidth();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
//result[i][j] = bufImg.getRGB(i, j) & 0xFFFFFF;
//System.out.println(bufImg.getRGB(i, j) );
/*if(bufImg.getRGB(i, j) > 0) {
System.out.println(i + "," + j);
}*/
int pixel = bufImg.getRGB(i, j); // 下面三行代碼将一個數字轉換為RGB數字
int a = (pixel & 0xff0000) >> 16;
int b = (pixel & 0xff00) >> 8;
int c = (pixel & 0xff);
if (a == 255 || b == 255 || c == 255) {
//System.out.println("i=" + i + ",j=" + j + ":(" + a + "," + b + "," + c + ")");
map.put(i, map.get(i) == null ? 1 : map.get(i) + 1);
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// System.out.println(map);
return map;
}
public static Map<Integer, Integer> getImageGRB(String filePath) {
File file = new File(filePath);
if(!file.exists()) {
return null;
}
try {
return getImageGRB(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
圖檔過濾方法
/***
* 高斯模糊處理
* @param src
* @return
*/
public static Mat gaussianBlur(Mat src) {
Mat dst = new Mat();
//參數 3 會影響圖檔處理結果
Imgproc.GaussianBlur(src, dst, new Size(3, 3), 0, 0, Core.BORDER_DEFAULT);
// Imgcodecs.imwrite("c:\\b1_1.jpg", binary);
return dst;
}
/**
* 圖檔灰階化處理
* @param src
* @return
*/
public static Mat gray(Mat src) {
Mat dst = new Mat();
Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2GRAY);
return dst;
}
/**
* 圖檔 二值化
* @param src
* @return
*/
public static Mat binary(Mat src) {
Mat dst = new Mat();
Imgproc.threshold(src, dst, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU); //一般
return dst;
}
/**
* 邊緣檢測
* @param src
* @return
*/
public static Mat canny(Mat src) {
Mat dst = new Mat();
// 這裡 200 300 會影響結果
Imgproc.Canny(src, dst, 200, 300);
return dst;
}