Java изображение обрезано - PullRequest
       3

Java изображение обрезано

7 голосов
/ 04 января 2012

Тот же вопрос, что и в прошлый раз, но я предоставлю более подробную информацию.В настоящее время я вращаю изображения, используя:

 int rotateNum //in main class

 double rotationRequired = Math.toRadians(rotateNum);

    double locationX = img.getWidth(this) / 2;
    double locationY = img.getHeight(this) / 2;
    AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
    AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);


    g2d.drawImage(op.filter((BufferedImage)img, null), imgX, imgY, null);

И затем я фактически поворачиваю изображение, используя:

double deltaX = (double)(imgY - otherImg.imgY);
double deltaY = (double)(imgX - otherImg.imgX);
rotateNum = (int)(180 * Math.atan2(deltaY, deltaX) / Math.PI);

Мои изображения различаются по размеру.Меньшие изображения не обрезаются (то есть обрезаются пробелами), а большие - слева или справа.Изменение размера изображений не работает, и я обрезал белый прямоугольник вокруг изображения с помощью GIMP.

Пример изображения: До (игнорируйте серую область слева)

После: см. Обрезание сбоку

Ответы [ 4 ]

3 голосов
/ 11 апреля 2016

Проблема в том, что ваше исходное изображение не совсем квадратичное.Когда вы реализуете вращение AffineTransform с помощью at.rotate (-rad, width / 2, height / 2) ;, это то же самое, что и:

at.translate(width/2,height/2);
at.rotate(rads);
at.translate(-width/2,-height/2);

Итак, когда он выполняет последнюю строку, он переводитк происхождению.И если ширина больше y (или наоборот), то источник преобразования будет переведен на меньшее расстояние, чем сторона большей длины.

Например, если ваша ширина равна 30, а вашавысота равна 60, тогда исходная точка будет установлена ​​как (-15, -30) от того места, где было установлено исходное преобразование.Таким образом, когда вы переводите его, скажем, на 90 градусов, изображение будет иметь ширину 60 и высоту 30, но в соответствии с исходной точкой исходное дно изображения будет нарисовано в (-30,0),поэтому он переполняет AffineTransform в -15 по оси X.Затем эта часть изображения будет обрезана.

Чтобы исправить это, вместо этого можно использовать следующий код:

double degreesToRotate = 90;
double locationX =bufferedImage.getWidth() / 2;
double locationY = bufferedImage.getHeight() / 2;

double diff = Math.abs(bufferedImage.getWidth() - bufferedImage.getHeight());

//To correct the set of origin point and the overflow
double rotationRequired = Math.toRadians(degreesToRotate);
double unitX = Math.abs(Math.cos(rotationRequired));
double unitY = Math.abs(Math.sin(rotationRequired));

double correctUx = unitX;
double correctUy = unitY;

//if the height is greater than the width, so you have to 'change' the axis to correct the overflow
if(bufferedImage.getWidth() < bufferedImage.getHeight()){
    correctUx = unitY;
    correctUy = unitX;
}

int posAffineTransformOpX = posX-(int)(locationX)-(int)(correctUx*diff);
int posAffineTransformOpY = posY-(int)(locationY)-(int)(correctUy*diff);

//translate the image center to same diff that dislocates the origin, to correct its point set
AffineTransform objTrans = new AffineTransform();
objTrans.translate(correctUx*diff, correctUy*diff);
objTrans.rotate(rotationRequired, locationX, locationY);

AffineTransformOp op = new AffineTransformOp(objTrans, AffineTransformOp.TYPE_BILINEAR);

// Drawing the rotated image at the required drawing locations
graphic2dObj.drawImage(op.filter(bufferedImage, null), posAffineTransformOpX, posAffineTransformOpY, null);

Надеюсь, это поможет.

2 голосов
/ 04 января 2012

Я полагаю, что важен не размер изображения, а его эксцентриситет: более квадратные изображения имеют меньшую проблему, чем изображения более толстые или более тонкие.думайте, что ваша проблема в том, что ваш центр вращения не должен быть [ширина / 2, высота / 2] - это не так просто.Вместо этого представьте, что изображение находится в левой верхней части большого квадрата, длина его стороны будет равна ширине или высоте изображения, в зависимости от того, что больше.Это то, что поворачивается всякий раз, когда вы поворачиваете свое изображение.

Например, см. Мой ответ здесь: https://stackoverflow.com/a/8720123/522444

1 голос
/ 04 января 2012

Поворот изображения также может повлиять на размер изображения.Вот код, который я нашел на старых форумах Sun давно (я забыл оригинальный постер).Он пересчитывает размер, необходимый для отображения изображения при заданном угле поворота:

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import javax.imageio.*;
import javax.swing.*;

public class RotateImage {
    public static void main(String[] args) throws IOException {
        URL url = new URL("https://blogs.oracle.com/jag/resource/JagHeadshot-small.jpg");
        BufferedImage original = ImageIO.read(url);
        GraphicsConfiguration gc = getDefaultConfiguration();
        BufferedImage rotated1 = tilt(original, -Math.PI/2, gc);
        BufferedImage rotated2 = tilt(original, +Math.PI/4, gc);
        BufferedImage rotated3 = tilt(original, Math.PI, gc);
        display(original, rotated1, rotated2, rotated3);
    }

    public static BufferedImage tilt(BufferedImage image, double angle, GraphicsConfiguration gc) {
        double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
        int w = image.getWidth(), h = image.getHeight();
        int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin);
        int transparency = image.getColorModel().getTransparency();
        System.out.println(transparency);
//        BufferedImage result = gc.createCompatibleImage(neww, newh, transparency);
        BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
        Graphics2D g = result.createGraphics();
        g.translate((neww-w)/2, (newh-h)/2);
        g.rotate(angle, w/2, h/2);
        g.drawRenderedImage(image, null);
        return result;
    }

    public static GraphicsConfiguration getDefaultConfiguration() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        return gd.getDefaultConfiguration();
    }

    public static void display(BufferedImage im1, BufferedImage im2, BufferedImage im3, BufferedImage im4) {
        JPanel cp = new JPanel(new GridLayout(2,2));
        addImage(cp, im1, "original");
        addImage(cp, im2, "rotate -PI/2");
        addImage(cp, im3, "rotate +PI/4");
        addImage(cp, im4, "rotate PI");

        JFrame f = new JFrame("RotateImage");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(cp);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    static void addImage(Container cp, BufferedImage im, String title) {
        JLabel lbl = new JLabel(new ImageIcon(im));
        lbl.setBorder(BorderFactory.createTitledBorder(title));
        cp.add(lbl);
    }
}
1 голос
/ 04 января 2012

Это то, что java делает, к сожалению. Один из способов решить эту проблему - сделать фигуру квадратной, чтобы при вращении не происходило срезания.

Эта проблема описана в книге Дэвида "Программирование игр на Java", books_google_killer + игра + программирование + вырезка + вращение , которая является замечательной книгой, если вы хотите сделать что-нибудь Java-программирование (даже если оно немного старое).

Редактировать :: Это преобразование изображения в квадрат можно сделать с необработанным изображением с помощью программного обеспечения для редактирования изображений или с помощью самой Java. Возможно, примените свой собственный метод вращения, который может проверять наличие таких столкновений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...