凸起效应算法的解释

时间:2014-04-02 22:06:38

标签: java image image-processing bufferedimage distortion

我是Java的初学者,只编写了一年。我的任务是对任何给定的图像造成扭曲。我最近在膨胀效应方面遇到了很多麻烦。我一直在谷歌周围进行研究,我发现这些链接非常有用:

https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm Image Warping - Bulge Effect Algorithm

我尝试了这两个链接给我的算法,但我最终没有任何结果。

我们说我已经导入了一个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;  
            }

问题是这段代码并没有真正凸显中间的图像。我制作了一个尺寸为1000x1000的新BufferedImage,因为原始像素的像素扩展得非常远,有些像素扩展到1000x1000以上。如果有人帮我展示这个代码中有关凸起效应的问题,我将不胜感激。

1 个答案:

答案 0 :(得分:4)

我认为问题的一个(主要)部分是你在像素中计算凸起效果的半径。虽然我没有阅读您链接的主题中的所有答案,但似乎它们指的是纹理坐标 - 即0到1之间的值。

除此之外:使用当前的方法,您将遇到抽样问题。想象一下,输入图像中心的一个像素将被拉伸&#34;这样它就可以覆盖输出图像中的10x10像素区域。但是,您仍然只计算此像素的一个新位置。

想象一下,就像你从输入图像中获取像素,并将它们移动到输出图像中的新位置 - 但你必须反过来做:你必须检查输出图像中的每个像素,并且计算输入图像的哪个像素在那里移动。

我创造了一个小例子:它允许移动放大镜&#34;用鼠标在图像上。使用鼠标滚轮,您可以改变失真的强度。使用SHIFT + MouseWheel,您可以更改放大镜的大小。

enter image description here

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);
                }
            }
        }
    }
}