java图像处理之实现任意角度图像旋转
原理及步驟:
1、旋轉角度:圖像順時針或逆時針旋轉的角度,以θ表示,需要用戶輸入;
2、旋轉中心:一般以圖像中心作為旋轉中心,周圍像素圍繞其旋轉;
3、畫布大小:由于圖像旋轉后產生的圖像寬和高與原始圖像不同,需要先計算好旋轉后的畫布大小。由于一般處理的圖像都是矩形陣列,不考慮特殊形狀前提下,我們只需要計算原始圖像四個角點坐標圍繞中心旋轉θ角度后的坐標,取X方向最大最小值之差作為畫布寬,Y方向最大最小值之差作為畫布高,以此生成一幅空圖像;
4、像素賦值:得到畫布圖像之后,將畫布坐標系與原始圖像坐標系進行統一,即畫布中心與原始圖像中心都改正為(0,0)位置,將畫布上每個像素進行θ角的反方向旋轉,即旋轉回原始圖像位置,如果旋轉后的像素落在原始圖像坐標范圍內,取該位置最近像素RGB值作為畫布上對應像素RGB值;
5、空像素處理:由于旋轉后,畫布上可能有部分區域在原圖沒有對應范圍,這部分像素為空像素,也可以叫做背景像素,這部分像素可以通過自定義背景色進行賦值。如果輸出圖片格式為jpg,由于Windows圖片瀏覽工具背景色為白色,建議將背景色輸出為白色;
6、背景色透明:如果需要將畫布中空像素設置為透明,需要在初始化畫布時將畫布類型設置為TYPE_INT_ARGB,即png圖像對應的格式,輸出時也輸出為png格式圖像即可。
圖像旋轉java實現:
1、由于java中math三角函數都是以弧度進行計算的,需要將角度轉換為弧度。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? double angle = theta * Math.PI / 180;
2、計算按照逆時針旋轉θ角度后畫布大小,即X和Y方向旋轉后最大最小值。因為旋轉為圖像中心,由于中心對稱,只需要計算對角線上其中一個坐標,對角線另一個取負即可,之后對四個值進行排序并返回排序后數組。取第一和第二象限兩個角點進行計算,先計算原圖第一象限角點相對坐標系弧度,第二象限相對坐標系弧度=π-第一象限弧度。
獲取X方向旋轉后坐標數組:先計算第一象限角點相對中心距離radius,計算該角點弧度angle1,通過反余弦計算得到,再通過計算原圖本身弧度加上旋弧度angle后的余弦。
private double[] getX(int i, int j, double angle) {double results[] = new double[4];double radius = Math.sqrt(i * i + j * j);double angle1 = Math.acos(i / radius);results[0] = radius * Math.cos(angle1 + angle);results[1] = radius * Math.cos(Math.PI - angle1 + angle);results[2] = -results[0];results[3] = -results[1];Arrays.sort(results);return results;}獲取Y方向旋轉后坐標數組:
private double[] getY(int i, int j, double angle) {double results[] = new double[4];double radius = Math.sqrt(i * i + j * j);double angle1 = Math.asin(j / radius);results[0] = radius * Math.sin(angle1 + angle);results[1] = radius * Math.sin(Math.PI - angle1 + angle);results[2] = -results[0];results[3] = -results[1];Arrays.sort(results);return results;}3、根據X和Y方向最大最小值作為寬和高生成畫布,畫布類型根據需要進行設置,需要輸出影像背景透明的png圖像,類型設置為BufferedImage.TYPE_INT_ARGB,如果原始圖像為png格式,也可以直接使用image.getType(),用原始圖像格式進行賦值。
int WIDTH = (int) (xCoords[3] - xCoords[0]);int HEIGHT = (int) (yCoords[3] - yCoords[0]);BufferedImage resultImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);4、對畫布每一個像素位置進行逐一計算,計算每個位置按照順時針旋轉θ角后位置,判斷該位置是否在原圖范圍內,在原圖范圍內,則直接取原圖上該位置rgb值對畫布對應像素進行賦值,原圖范圍以外的,通過預先傳入的背景色參數進行賦值。由于畫布上像素相對坐標系弧度是通過反余弦函數計算的,反余弦取值為(0,π),對于第三四象限的像素,通過判斷y坐標是否大于0,大于0則直接計算,小于0,說明該像素位于三四象限,通過計算2π減去反余弦后弧度得到該像素相對坐標系弧度。
for (int i = 0; i < WIDTH; i++) {for (int j = 0; j < HEIGHT; j++) {int x = i - WIDTH / 2;int y = HEIGHT / 2 - j;double radius = Math.sqrt(x * x + y * y);double angle1;if (y > 0) {angle1 = Math.acos(x / radius);} else {angle1 = 2 * Math.PI - Math.acos(x / radius);}x = (int) (radius * Math.cos(angle1 - angle));y = (int) (radius * Math.sin(angle1 - angle));if (x < (width / 2) & x > -(width / 2) & y < (height / 2) & y > -(height / 2)) {int rgb = image.getRGB(x + width / 2, height / 2 - y);resultImage.setRGB(i, j, rgb);}else {int rgb = ((0 & 0xff) << 24) | ((backgroundColor.getRed() & 0xff) << 16) | ((backgroundColor.getGreen() & 0xff) << 8)| ((backgroundColor.getBlue() & 0xff));resultImage.setRGB(i, j, rgb);}}}5、完整的程序實現及測試
public class ImageRotate {/*** 創建任意角度的旋轉圖像* @param image* @param theta* @param backgroundColor* @return*/public BufferedImage rotateImage(BufferedImage image, double theta,Color backgroundColor) {int width = image.getWidth();int height = image.getHeight();double angle = theta * Math.PI / 180; // 度轉弧度double[] xCoords = getX(width / 2, height / 2, angle);double[] yCoords = getY(width / 2, height / 2, angle);int WIDTH = (int) (xCoords[3] - xCoords[0]);int HEIGHT = (int) (yCoords[3] - yCoords[0]);BufferedImage resultImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);for (int i = 0; i < WIDTH; i++) {for (int j = 0; j < HEIGHT; j++) {int x = i - WIDTH / 2;int y = HEIGHT / 2 - j;double radius = Math.sqrt(x * x + y * y);double angle1;if (y > 0) {angle1 = Math.acos(x / radius);} else {angle1 = 2 * Math.PI - Math.acos(x / radius);}x = (int) (radius * Math.cos(angle1 - angle));y = (int) (radius * Math.sin(angle1 - angle));if (x < (width / 2) & x > -(width / 2) & y < (height / 2) & y > -(height / 2)) {int rgb = image.getRGB(x + width / 2, height / 2 - y);resultImage.setRGB(i, j, rgb);}else {int rgb = ((0 & 0xff) << 24) | ((backgroundColor.getRed() & 0xff) << 16) | ((backgroundColor.getGreen() & 0xff) << 8)| ((backgroundColor.getBlue() & 0xff));resultImage.setRGB(i, j, rgb);}}}return resultImage;}// 獲取四個角點旋轉后Y方向坐標private double[] getY(int i, int j, double angle) {double results[] = new double[4];double radius = Math.sqrt(i * i + j * j);double angle1 = Math.asin(j / radius);results[0] = radius * Math.sin(angle1 + angle);results[1] = radius * Math.sin(Math.PI - angle1 + angle);results[2] = -results[0];results[3] = -results[1];Arrays.sort(results);return results;}// 獲取四個角點旋轉后X方向坐標private double[] getX(int i, int j, double angle) {double results[] = new double[4];double radius = Math.sqrt(i * i + j * j);double angle1 = Math.acos(i / radius);results[0] = radius * Math.cos(angle1 + angle);results[1] = radius * Math.cos(Math.PI - angle1 + angle);results[2] = -results[0];results[3] = -results[1];Arrays.sort(results);return results;}public static void main(String[] args) throws Exception {File input = new File("C:/Users/admin/Desktop/1.jpg");File output = new File("C:/Users/admin/Desktop/2.png");BufferedImage image = ImageIO.read(input);Color bgColor = new Color(255, 255, 255);BufferedImage result = new ImageRotate().rotateImage(image, 45,bgColor);ImageIO.write(result, "png", output);} }測試圖像:
旋轉45度后生成的png圖像:
?
?
總結
以上是生活随笔為你收集整理的java图像处理之实现任意角度图像旋转的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java图像处理之查找表实现图像处理加速
- 下一篇: OpenCV直线和圆形检测