java opencv 獲取圖中物品的傾斜角度(單個物品,如果存在多個物品,建議先將多個物品處理成一個整體或分別切割開處理)

Lee597發表於2024-08-21
// 1、先連上opencv包

System.setProperty("java.awt.headless", "false");
System.out.println(System.getProperty("java.library.path"));
URL url = ClassLoader.getSystemResource("lib/opencv/opencv_java4100.dll");
System.load(url.getPath());

// 2、計算傾斜的角度
String filePath = "需要處理的檔案路徑";
Mat src = Imgcodecs.imread(filePath);
Mat gary = new Mat();
Imgproc.cvtColor(src, gary, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(gary, gary, new Size(3, 3), 0);
Imgproc.GaussianBlur(gary, gary, new Size(3, 3), 0);
Mat edge = new Mat();
Imgproc.Canny(gary, edge, 30, 50);

Mat lines = new Mat();
Imgproc.HoughLinesP(edge, lines, 1, Math.PI/180, 100, 50, 10);

double angle = 0.0;
for (int i = 0; i < lines.cols(); i++) {
double rho = lines.get(0, i)[0];
double theta = lines.get(0, i)[1];
double cosTheta = Math.cos(theta);
double sinTheta = Math.sin(theta);
double x0 = rho * cosTheta;
double y0 = rho * sinTheta;
double x1 = x0 + 1000 * (-sinTheta);
double y1 = y0 + 1000 * (cosTheta);
double x2 = x0 - 1000 * (-sinTheta);
double y2 = y0 - 1000 * (cosTheta);

angle += Math.atan2(y2 - y1, x2 - x1) * 180.0 / Math.PI;
}
angle /= lines.cols();
System.out.println("angle = " + angle);

if (angle < 0){
angle = 180 - angle;
}


// 3、旋轉影像並顯示,其實opencv也可以旋轉影像,但效果感覺不如Java

BufferedImage image = ImageIO.read(new File(filePath));
BufferedImage rotate = ImageUtils.Rotate(image, angle);

BufferedImage grayImage = new BufferedImage(rotate.getWidth(),rotate.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
ColorConvertOp op = new ColorConvertOp(null);
grayImage = op.filter(rotate, grayImage);

Mat src = Mat.zeros(new Size(rotate.getWidth(), rotate.getHeight()), CvType.CV_8UC3);

byte[] imageData = ((DataBufferByte) grayImage.getRaster().getDataBuffer()).getData();
src.put(0,0,imageData);

HighGui.namedWindow("dst", HighGui.WINDOW_NORMAL);
HighGui.resizeWindow("dst", 1600, 900);
HighGui.imshow("dst", dst);
HighGui.waitKey(0);

src.release();
gary.release();
edge.release();
lines.release();
HighGui.destroyAllWindows();
System.exit(0);









// 上面 ImageUtils.Rotate是一個自定義的旋轉方法,具體程式碼如下:

    //region 圖片旋轉
/**

* 對圖片進行旋轉

*

* @param src 被旋轉圖片

* @param angel 旋轉角度

* @return 旋轉後的圖片

*/

public static BufferedImage Rotate(Image src, int angel) {

int src_width = src.getWidth(null);

int src_height = src.getHeight(null);

// 計算旋轉後圖片的尺寸

Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(

src_width, src_height)), angel);

BufferedImage res = null;

res = new BufferedImage(rect_des.width, rect_des.height,

BufferedImage.TYPE_INT_RGB);

Graphics2D g2 = res.createGraphics();

// 進行轉換

g2.translate((rect_des.width - src_width) / 2,

(rect_des.height - src_height) / 2);

g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

g2.drawImage(src, null, null);

return res;

}

/**

* 計算旋轉後的圖片

*

* @param src 被旋轉的圖片

* @param angel 旋轉角度

* @return 旋轉後的圖片

*/

public static Rectangle CalcRotatedSize(Rectangle src, int angel) {

// 如果旋轉的角度大於90度做相應的轉換

if (angel >= 90) {

if (angel / 90 % 2 == 1) {

int temp = src.height;

src.height = src.width;

src.width = temp;

}

angel = angel % 90;

}

double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;

double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;

double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;

double angel_dalta_width = Math.atan((double) src.height / src.width);

double angel_dalta_height = Math.atan((double) src.width / src.height);

int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha

- angel_dalta_width));

int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha

- angel_dalta_height));

int des_width = src.width + len_dalta_width * 2;

int des_height = src.height + len_dalta_height * 2;

return new Rectangle(new Dimension(des_width, des_height));

}

//endregion



相關文章