java - 凸起效应算法说明

标签 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 像素 x 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 之外。如果有人能帮助我展示这段代码中有关凸起效果的问题,我将不胜感激。

最佳答案

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

除此之外:使用当前的方法,您将遇到采样问题。想象一下,输入图像中心的一个像素将被“拉伸(stretch)”,以便它覆盖输出图像中的 10x10 像素区域。但是,您仍然只是计算该像素的一个新位置。

想象一下,您正在从输入图像中获取像素,并将它们移动到输出图像中的新位置 - 但您必须以相反的方式进行操作:您必须检查输出图像中的每个像素,并且计算输入图像的哪个像素被移动到那里。

我创建了一个小示例:它允许使用鼠标在图像上移动“放大镜”。使用鼠标滚轮可以更改扭曲的强度。使用 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);
                }
            }
        }
    }
}

关于java - 凸起效应算法说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22824041/

相关文章:

image - 我如何使用 Canvas 绘制这个背景形状?

java - 添加 JLabel 作为 JPanel 的背景

android - 如何在不损失 Android 分辨率的情况下减小位图的大小?

c# - 在另一个大图像中快速找到一个较小的图像

java - 哈希用户密码并检查Android中数据库中的哈希值

java - 如何从 loadContent() 将 html 和 javascript 加载到 webengine 中?

c# - 将 BLOB 作为 Image C# 保存到磁盘

Codeigniter 图像调整大小?

java - Firebase 安卓代理设置

java - 如何在java中将2018年12月17日到2018年12月17日的日期转换为字符串。我想将其存储到MYSQL数据库