简体   繁体   English

凸出效果算法的说明

[英]Explanation for the bulge effect algorithm

I am a beginner at Java, only been coding for a year. 我是Java的初学者,仅编码一年。 My task is to create distortions to any image given. 我的任务是使给定的任何图像变形。 I have been having a lot of trouble with the bulge effect lately. 最近,我在凸出效果方面遇到了很多麻烦。 I have been researching all around google and I found these links very helpful: 我一直在谷歌周围进行研究,发现这些链接非常有帮助:

https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm Image Warping - Bulge Effect Algorithm https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm 图像扭曲-凸起效果算法

I tried the algorithm that these two links gave me, but I ended up with nothing. 我尝试了这两个链接给我的算法,但最终没有结果。

Let's say I have imported an image that is 100 pixels by 100 pixels, from the code below, am I using the algorithm correctly: 假设我从下面的代码中导入的图像是100像素乘100像素,是否正确使用了算法:

//modifiedImage is a global variable and contains the image that is 100x100    
    public BufferedImage buldge(){
                double X = 0;
                double Y = 0;
                BufferedImage anImage = new BufferedImage (1000, 1000, BufferedImage.TYPE_INT_ARGB);
                for(int x = 0; x < modifiedImage.getWidth(); x++){
                    for(int y = 0; y < modifiedImage.getHeight(); y++){
                            int rgb = modifiedImage.getRGB(x, y);
                            double newRadius = 0;
                            X = x - x/2;
                            Y = y - y/2;
                            double radius =  Math.sqrt(X*X + Y*Y);
                            double angle = Math.atan2(X, Y);
                            newRadius = Math.pow(radius,1.5);
                            X = (int)(newRadius*Math.sin(angle));
                            Y = (int)(newRadius*Math.cos(angle));
                            anImage.setRGB((int)X, (int)Y,rgb);

                    }
                }
                return anImage;  
            }

The problem is that this code doesn't really bulge the image in the middle. 问题在于该代码实际上不会在中间突出图像。 I have made a new BufferedImage of dimensions 1000x1000 because the pixels from the original one gets extended really far and some are extended beyond 1000x1000. 我制作了一个尺寸为1000x1000的新BufferedImage,因为来自原始像素的像素实际上已扩展得很远,而有些像素已扩展到1000x1000以上。 If anyone would help me show the problems in this code concerning the bulge effect, I would greatly appreciate it. 如果有人能帮助我说明这段代码中关于凸起效果的问题,我将不胜感激。

I think one (main) part of the problem is that you are computing the radius of the bulge effect in pixels . 我认为问题的一个(主要)部分是您正在计算以像素为单位的凸起效果的半径。 Although I have not read all anwers in the threads that you linked, it seems like they are referring to texture coordinates - that is, to values between 0 and 1. 尽管我还没有阅读所链接线程中的所有anwer,但似乎它们引用的是纹理坐标 -即0到1之间的值。

Apart from that: With the current approach, you will have a sampling problem. 除此之外:使用当前方法,您将遇到抽样问题。 Imagine that one pixel at the center of the input image will be "stretched" so that it covers an area of, say, 10x10 pixels in the output image. 想象一下, 输入图像中心的一个像素将被“拉伸”,以使其覆盖输出图像中的10x10像素区域。 But still, you are only computing one new position for this pixel. 但是,您仍然只为此像素计算一个新位置。

Imagine it like you are taking pixels from the input image, and move them to a new position in the output image - but you have to do it the other way around: You have to check each pixel in the output image, and compute which pixel of the input image was moved there. 想象一下,就像您要从输入图像中获取像素,然后将它们移动到输出图像中的新位置一样,但是您必须采用另一种方法:您必须检查输出图像中的每个像素,并计算出哪个像素输入图像的移到了那里。

I created a small example: It allows moving a "magnifying glass" over the image with the mouse. 我创建了一个小示例:它允许使用鼠标在图像上移动“放大镜”。 With the mouse wheel, you can change the strength of the distortion. 使用鼠标滚轮,可以更改变形的强度。 With SHIFT+MouseWheel, you can change the size of the magnifying glass. 使用SHIFT + MouseWheel,您可以更改放大镜的大小。

在此处输入图片说明

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.beans.Transient;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ImageBulgeTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new GridLayout(1, 1));
        frame.getContentPane().add(new ImageBulgePanel());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}


class ImageBulgePanel extends JPanel
{
    private BufferedImage input;
    private BufferedImage output;
    private double bulgeStrength = 0.3;
    private double bulgeRadius = 100;

    ImageBulgePanel()
    {
        try
        {
            input = ImageIO.read(new File("lena512color.png"));
        }
        catch (IOException e1)
        {
            e1.printStackTrace();
        }

        addMouseMotionListener(new MouseAdapter()
        {
            @Override
            public void mouseMoved(MouseEvent e)
            {
                updateImage(e.getX(), e.getY());
            }
        });
        addMouseWheelListener(new MouseWheelListener()
        {

            @Override
            public void mouseWheelMoved(MouseWheelEvent e)
            {
                if ((e.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) ==
                    InputEvent.SHIFT_DOWN_MASK)
                {
                    bulgeRadius += 10 * e.getWheelRotation();
                    System.out.println("bulgeRadius "+bulgeRadius);
                }
                else
                {
                    bulgeStrength += 0.1 * e.getWheelRotation();
                    bulgeStrength = Math.max(0, bulgeStrength);
                    System.out.println("bulgeStrength "+bulgeStrength);
                }
                updateImage(e.getX(), e.getY());
            }
        });
    }

    @Override
    @Transient
    public Dimension getPreferredSize()
    {
        if (isPreferredSizeSet())
        {
            return super.getPreferredSize();
        }
        return new Dimension(input.getWidth(), input.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if (output != null)
        {
            g.drawImage(output, 0, 0, null);
        }
    }

    private void updateImage(int x, int y)
    {
        if (output == null)
        {
            output = new BufferedImage(
                input.getWidth(), input.getHeight(), 
                BufferedImage.TYPE_INT_ARGB);
        }
        computeBulgeImage(input, x, y, 
            bulgeStrength, bulgeRadius, 
            output);
        repaint();
    }

    private static void computeBulgeImage(
        BufferedImage input, int cx, int cy, 
        double bulgeStrength, double bulgeRadius, 
        BufferedImage output)
    {
        int w = input.getWidth();
        int h = input.getHeight();
        for(int x = 0; x < w; x++)
        {
            for(int y = 0; y < h; y++)
            {
                int dx = x-cx;
                int dy = y-cy;
                double distanceSquared = dx * dx + dy * dy;;
                int sx = x;
                int sy = y;
                if (distanceSquared < bulgeRadius * bulgeRadius)
                {
                    double distance = Math.sqrt(distanceSquared);
                    boolean otherMethod = false;
                    otherMethod = true;
                    if (otherMethod)
                    {
                        double r = distance / bulgeRadius;
                        double a = Math.atan2(dy, dx);
                        double rn = Math.pow(r, bulgeStrength)*distance; 
                        double newX = rn*Math.cos(a) + cx; 
                        double newY = rn*Math.sin(a) + cy;  
                        sx += (newX - x);
                        sy += (newY - y);
                    }
                    else
                    {
                        double dirX = dx / distance;
                        double dirY = dy / distance;
                        double alpha = distance / bulgeRadius;
                        double distortionFactor = 
                            distance * Math.pow(1-alpha, 1.0 / bulgeStrength);
                        sx -= distortionFactor * dirX;
                        sy -= distortionFactor * dirY;
                    }
                }
                if (sx >= 0 && sx < w && sy >= 0 && sy < h)
                {
                    int rgb = input.getRGB(sx, sy);
                    output.setRGB(x, y, rgb);
                }
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM