java 读取图片RGB每次值不一致

为了进行图片相似度匹配,最近在做java的dHash,pHash和aHash等算法

读取网络图片ImageIO.read()之后,再读取每个像素点上的getRGB

发现每次得到rgb的值都会存在差异,造成对hash算法对同样url的图片生成的指纹每次都会不一致

造成匹配结果有误差

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;


/**
 * 差异值Hash:差异值哈希。精确度较高,且速度也非常快。
 * <p>
 * ①图片缩放为9*8大小
 * <p>
 * ②将图片灰度化
 * <p>
 * ③差异值计算(每行相邻像素的差值,这样会生成8*8的差值,前一个像素大于后一个像素则为1,否则为0)
 * <p>
 * ④生成哈希值
 */
public class DHashUtil {
    /**
     * 计算dHash方法
     *
     * @param url 文件
     * @return hash
     */
    public static String getDHash(String url) {
        //读取文件
        BufferedImage srcImage = getRemoteBufferedImage(url);

        //文件转成9*8像素,为算法比较通用的长宽
        BufferedImage buffImg = new BufferedImage(9, 8, BufferedImage.TYPE_INT_RGB);
        buffImg.getGraphics().drawImage(srcImage.getScaledInstance(9, 8, Image.SCALE_SMOOTH), 0, 0, null);

        int width = buffImg.getWidth();
        int height = buffImg.getHeight();
        int[][] grayPix = new int[width][height];
        StringBuffer figure = new StringBuffer();

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                //图片灰度化
                int rgb = buffImg.getRGB(x, y);
                int r = rgb >> 16 & 0xff;
                int g = rgb >> 8 & 0xff;
                int b = rgb & 0xff;
                int gray = (r * 30 + g * 59 + b * 11) / 100;
                grayPix[x][y] = gray;

                //开始计算dHash 总共有9*8像素 每行相对有8个差异值 总共有 8*8=64 个
                if (x != 0) {
                    long bit = grayPix[x - 1][y] > grayPix[x][y] ? 1 : 0;
                    figure.append(bit);
                }
            }
        }

        return figure.toString();
    }

    /**
     * 计算海明距离
     * <p>
     * 原本用于编码的检错和纠错的一个算法
     * 现在拿来计算相似度,如果差异值小于一定阈值则相似,一般经验值小于5为同一张图片
     *
     * @param str1
     * @param str2
     * @return 距离
     */
    public static long getHammingDistance(String str1, String str2) {
        int distance;
        if (str1 == null || str2 == null || str1.length() != str2.length()) {
            distance = -1;
        } else {
            distance = 0;
            for (int i = 0; i < str1.length(); i++) {
                if (str1.charAt(i) != str2.charAt(i)) {
                    distance++;
                }
            }
        }
        return distance;
    }
    /**
     * 获取远程网络图片信息
     * @param imageURL
     * @return
     */
    public static BufferedImage getRemoteBufferedImage(String imageURL) {
        URL url = null;
        InputStream is = null;
        BufferedImage bufferedImage = null;
        try {
            url = new URL(imageURL);
            is = url.openStream();
            bufferedImage = ImageIO.read(is);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            System.out.println("imageURL: " + imageURL + ",无效!");
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("imageURL: " + imageURL + ",读取失败!");
            return null;
        } finally {
            try {
                if (is!=null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("imageURL: " + imageURL + ",流关闭异常!");
                return null;
            }
        }
        return bufferedImage;
    }

    //DHashUtil 参数值为待处理文件夹
    public static void main(String[] args) {
        //读取文件
        BufferedImage srcImage1 = getRemoteBufferedImage("https://wx.qlogo.cn/mmhead/ver_1/rWO0bKnehTEeH64ibicoWESgJSUOtQiaqJPwx0003aszhPlUhpTc8ZuGwhF3Rr1ibVmJhfKBN2DSHF7WG3vHHCHyZA/96");
        BufferedImage srcImage2 = getRemoteBufferedImage("https://wx.qlogo.cn/mmhead/ver_1/rWO0bKnehTEeH64ibicoWESgJSUOtQiaqJPwx0003aszhPlUhpTc8ZuGwhF3Rr1ibVmJhfKBN2DSHF7WG3vHHCHyZA/96");

        StringBuffer figure1 = new StringBuffer();
        StringBuffer figure2 = new StringBuffer();

        for (int y = 0; y < srcImage1.getHeight(); y++) {
            for (int x = 0; x < srcImage1.getWidth(); x++) {
                int rgb = srcImage1.getRGB(x, y);
                figure1.append(rgb);
            }
        }
        for (int y = 0; y < srcImage2.getHeight(); y++) {
            for (int x = 0; x < srcImage2.getWidth(); x++) {
                int rgb = srcImage2.getRGB(x, y);
                figure2.append(rgb);
            }
        }
        if (StringUtils.equals(figure1.toString(), figure2.toString())) {
            System.out.println("相同!");
        } else {
            System.out.println("不相同!");
        }


    }
}

执行main的结果就是"不相同",这一点的原因尚不清楚,怎么避免网上相关资料也没有查询到,不知道有没有人能给下解答?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您不想使用 Canvas API 绘制图片来获取 RGB ,也可以使用 JavaScript 中的 Image 对象来获取图片RGB 。不过需要注意的是,这种方法只适用于同域的图片,因为跨域图片会触发浏览器的跨域保护机制。 具体操作步骤如下: 1. 创建一个 Image 对象,并设置其 src 属性为要获取 RGB 图片地址: ```javascript var img = new Image(); img.src = 'your-image-url'; ``` 2. 将 Image 对象绘制到一个 Canvas 上: ```javascript var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); context.drawImage(img, 0, 0); var imageData = context.getImageData(0, 0, canvas.width, canvas.height); var pixels = imageData.data; // 每个像素点的 RGB 存储在一维数组中 ``` 这样,pixels 数组中每四个元素代表一个像素点的 RGBA ,即数组中第一个元素为红色通道的,第二个元素为绿色通道的,第三个元素为蓝色通道的,第四个元素为透明度的。因此,获取一个像素点的 RGB 可以通过下面的方式: ```javascript var pixelIndex = (y * canvas.width + x) * 4; // 根据像素点的坐标计算出在数组中的位置 var red = pixels[pixelIndex]; var green = pixels[pixelIndex + 1]; var blue = pixels[pixelIndex + 2]; ``` 其中 x 和 y 分别为像素点在图片中的横纵坐标。 需要注意的是,如果图片没有加载完成,getImageData() 方法会抛出 SecurityError 异常。因此,最好在 Image 对象的 onload 事件中执行绘制和获取 RGB 的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值