.jpe 和 .jxr 文件扩展名的 Java PhotoHashing 问题

Java PhotoHashing problem with .jpe and .jxr file extensions

提问人:upd 提问时间:11/13/2023 更新时间:11/13/2023 访问量:17

问:

我写了一个代码来扫描目录并为照片提供 pHash。问题是,当我为 8 张具有不同扩展名的相同照片指定路径时,即(.bmp .jpe .jpeg .jpeg .jpg .jpg .jxr .png .tif .tiff),它只计算其中 6 张的 pHash(它不会为 .jpe 和 .jxr 执行此操作)。终端是这样说的:

File: pepedefault.bmp, pHash: 111111111111111000000111111111111111111000000000000111111111111100000000000000011111111111000000000000000011111111110100000000000000001111111000000000000000000001111100000000000000000000001111000000000000000000000001110000000000000000000000001100000000000000000001000001100000000000000000011100000100000000000000000011100000000000000010000000011100000100000000011000000011100000100000000111000000011100000100000000100000000011100000110000000111000000011100000110000001000000000011100000100000001010000000011100001100000001100000000011100001000000001110000000001100001000000001110000000001100001000000000110000000001100001100000001110000000001100011100000001110000000011100011110000001000000000011100111111100001110000000011100111111100010100000000011111111111110010100000000011111111111111011100111000111111111111111001101111110111111111111111111111111111111111111
net.coobird.thumbnailator.tasks.UnsupportedFormatException: No suitable ImageWriter found for jpe.
    at net.coobird.thumbnailator.tasks.io.FileImageSink.isMatchingFormat(Unknown Source)
    at net.coobird.thumbnailator.tasks.io.FileImageSink.write(Unknown Source)
    at net.coobird.thumbnailator.tasks.SourceSinkThumbnailTask.write(Unknown Source)
    at net.coobird.thumbnailator.Thumbnailator.createThumbnail(Unknown Source)
    at net.coobird.thumbnailator.Thumbnails$Builder.toFile(Unknown Source)
    at org.example.PhotoHashing.resizeImage(PhotoHashing.java:86)
    at org.example.PhotoHashing.computePHash(PhotoHashing.java:59)
    at org.example.PhotoHashing.main(PhotoHashing.java:24)
File: pepedefault.jpeg, pHash: 111111111111110000000011111111111111110000000000000111111111111100000000000000011111111111000000000000000011111111110000000000000000001111111000000000000000000001111100000000000000000000001111000000000000000000000001110000000000000000000000001100000000000000000000000000100000000000000000011100000100000000000000000011100000000000000011000000011100000000000000011000000011100000100000000111000000011100000100000000100000000011100000110000000111000000011100000110000001000000000011100000100000001010000000011100000100000001100000000011100001000000001110000000001100001000000000110000000001100001000000001110000000001110001100000001110000000001110011100000001110000000001100011110000001000000000001110111111100001110000000011110111111100010100000000010111111111110010100000000011111111111110011100111000011111111111111001101111110111111111111111111111111111111111111
File: pepedefault.tif, pHash: 111111111111111000000111111111111111111000000000000111111111111100000000000000011111111111000000000000000011111111110100000000000000001111111000000000000000000001111100000000000000000000001111000000000000000000000001110000000000000000000000001100000000000000000001000001100000000000000000011100000100000000000000000011100000000000000010000000011100000100000000011000000011100000100000000111000000011100000100000000100000000011100000110000000111000000011100000110000001000000000011100000100000001010000000011100001100000001100000000011100001000000001110000000001100001000000001110000000001100001000000000110000000001100001100000001110000000001100011100000001110000000011100011110000001000000000011100111111100001110000000011100111111100010100000000011111111111110010100000000011111111111111011100111000111111111111111001101111110111111111111111111111111111111111111
File: pepedefault.tiff, pHash: 111111111111111000000111111111111111111000000000000111111111111100000000000000011111111111000000000000000011111111110100000000000000001111111000000000000000000001111100000000000000000000001111000000000000000000000001110000000000000000000000001100000000000000000001000001100000000000000000011100000100000000000000000011100000000000000010000000011100000100000000011000000011100000100000000111000000011100000100000000100000000011100000110000000111000000011100000110000001000000000011100000100000001010000000011100001100000001100000000011100001000000001110000000001100001000000001110000000001100001000000000110000000001100001100000001110000000001100011100000001110000000011100011110000001000000000011100111111100001110000000011100111111100010100000000011111111111110010100000000011111111111111011100111000111111111111111001101111110111111111111111111111111111111111111
File: pepedefault.jpg, pHash: 111111111111110000000011111111111111110000000000000111111111111100000000000000011111111111000000000000000011111111110000000000000000001111111000000000000000000001111100000000000000000000001111000000000000000000000001110000000000000000000000001100000000000000000000000000100000000000000000011100000100000000000000000011100000000000000011000000011100000000000000011000000011100000100000000111000000011100000100000000100000000011100000110000000111000000011100000110000001000000000011100000100000001010000000011100000100000001100000000011100001000000001110000000001100001000000000110000000001100001000000001110000000001110001100000001110000000001110011100000001110000000001100011110000001000000000001110111111100001110000000011110111111100010100000000010101111111110010100000000011111111111110011100111000011111111111111001101111110111111111111111111111111111111111111
File: pepedefault.png, pHash: 111111111111111000000111111111111111111000000000000111111111111100000000000000011111111111000000000000000011111111110100000000000000001111111000000000000000000001111100000000000000000000001111000000000000000000000001110000000000000000000000001100000000000000000001000001100000000000000000011100000100000000000000000011100000000000000010000000011100000100000000011000000011100000100000000111000000011100000100000000100000000011100000110000000111000000011100000110000001000000000011100000100000001010000000011100001100000001100000000011100001000000001110000000001100001000000001110000000001100001000000000110000000001100001100000001110000000001100011100000001110000000011100011110000001000000000011100111111100001110000000011100111111100010100000000011111111111110010100000000011111111111111011100111000111111111111111001101111110111111111111111111111111111111111111

为了准确起见,我将提供我使用的文件,即: pom.xml PhotoHashing.java DCT.java

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>HashPicks</artifactId>
    <version>1.0-SNAPSHOT</version>
    <repositories>
        <repository>
            <id>downgoon</id>
            <url>https://raw.githubusercontent.com/downgoon/maven-repo/master/repository</url>
        </repository>
    </repositories>


    <dependencies>
        <!-- Thumbnailator -->
        <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.14</version>
        </dependency>

        <dependency>
            <groupId>javax.media</groupId>
            <artifactId>jai_core</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>javax.media</groupId>
            <artifactId>jai_core</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-jpeg</artifactId>
            <version>3.10.1</version>
        </dependency>
        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-tiff</artifactId>
            <version>3.10.1</version>
        </dependency>

        <!--
        Optional dependency. Needed only if you deploy ImageIO plugins as part of a web app.
        Make sure you add the IIOProviderContextListener to your web.xml, see above.
        -->
        <dependency>
            <groupId>com.twelvemonkeys.servlet</groupId>
            <artifactId>servlet</artifactId>
            <version>3.10.1</version>
        </dependency>

        <!--
        Or Jakarta version, for Servlet API 5.0
        -->
        <dependency>
            <groupId>com.twelvemonkeys.servlet</groupId>
            <artifactId>servlet</artifactId>
            <version>3.10.1</version>
            <classifier>jakarta</classifier>
        </dependency>

        <dependency>
            <groupId>com.github.downgoon</groupId>
            <artifactId>MarvinFramework</artifactId>
            <version>1.5.5</version>
        </dependency>
        <!-- Thanks for using https://jar-download.com -->


        <!-- Marvin Image Processing Framework -->
        <dependency>
            <groupId>com.github.downgoon</groupId>
            <artifactId>marvin</artifactId>
            <version>1.5.5</version>
        </dependency>

    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

PhotoHashing.java

package org.example;

import net.coobird.thumbnailator.Thumbnails;
import marvin.image.MarvinImage;
import marvin.io.MarvinImageIO;
import marvin.plugin.MarvinImagePlugin;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class PhotoHashing {

    public static void main(String[] args) {
        // Путь к директории с фотографиями
        String directoryPath = "/Users/dark_kat/Downloads/pepe";

        // Получаем список файлов в директории
        List<File> imageFiles = getSupportedImageFiles(directoryPath);

        // Вычисляем и выводим pHash для каждой фотографии
        for (File imageFile : imageFiles) {
            try {
                String pHash = computePHash(imageFile);
                System.out.println("File: " + imageFile.getName() + ", pHash: " + pHash);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static List<File> getSupportedImageFiles(String directoryPath) {
        // Получаем список поддерживаемых изображений из директории
        List<File> imageFiles = new ArrayList<>();
        File directory = new File(directoryPath);

        if (directory.isDirectory()) {
            for (File file : directory.listFiles()) {
                if (file.isFile() && isSupportedImage(file)) {
                    imageFiles.add(file);
                }
            }
        }

        return imageFiles;
    }

    private static boolean isSupportedImage(File file) {
        // Проверяем, является ли файл поддерживаемым изображением
        String fileName = file.getName().toLowerCase();
        return fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".jpe") ||
                fileName.endsWith(".png") || fileName.endsWith(".tif") || fileName.endsWith(".tiff") ||
                fileName.endsWith(".svg") || fileName.endsWith(".bmp") || fileName.endsWith(".webp") ||
                fileName.endsWith(".jfif");
    }

    private static String computePHash(File imageFile) throws IOException {
        // Изменяем размер изображения
        File resizedImage = resizeImage(imageFile);

        // Загружаем изображение
        MarvinImage image = MarvinImageIO.loadImage(resizedImage.getPath());

        // Выполняем дискретное косинусное преобразование (DCT)
        MarvinImagePlugin dct = new DCT();
        dct.process(image, image);

        // Вычисляем среднее значение DCT
        double averageDCT = computeAverageDCT(image);

        // Ещё сокращаем DCT
        reduceDCT(image, averageDCT);

        // Построим хэш
        String pHash = buildHash(image);

        // Удаляем временные файлы
        resizedImage.delete();

        return pHash;
    }

    private static File resizeImage(File originalImage) throws IOException {
        // Изменяем размер изображения до 32x32 пикселей
        File resizedImage = new File("resized_" + originalImage.getName());
        Thumbnails.of(originalImage).size(32, 32).toFile(resizedImage);
        return resizedImage;
    }

    private static double computeAverageDCT(MarvinImage image) {
        // Вычисляем среднее значение DCT
        double sum = 0;
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                sum += image.getIntComponent0(x, y);
            }
        }
        return sum / (image.getWidth() * image.getHeight());
    }

    private static void reduceDCT(MarvinImage image, double averageDCT) {
        // Сокращаем DCT
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                if (image.getIntComponent0(x, y) > averageDCT) {
                    image.setIntColor(x, y, 255, 255, 255);
                } else {
                    image.setIntColor(x, y, 0, 0, 0);
                }
            }
        }
    }

    private static String buildHash(MarvinImage image) {
        // Построим хэш, представляющий изображение
        StringBuilder hash = new StringBuilder();
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                hash.append(image.getIntComponent0(x, y) > 0 ? "1" : "0");
            }
        }
        return hash.toString();
    }
}

DCT.java

// Путь к файлу: src/main/java/com/example/imageprocessing/DCT.java

package org.example;

import marvin.gui.MarvinAttributesPanel;
import marvin.gui.MarvinImagePanel;
import marvin.image.MarvinImage;
import marvin.image.MarvinImageMask;
import marvin.plugin.MarvinImagePlugin;
import marvin.util.MarvinAttributes;

import java.util.List;

public class DCT implements MarvinImagePlugin {

    public void process(MarvinImage imageIn, MarvinImage imageOut, int x, int y, int width, int height) {
        int[][] pixels = new int[width][height];

        // Заполняем массив значениями пикселей изображения
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                pixels[i][j] = imageIn.getIntComponent0(x + i, y + j);
            }
        }

        // Выполняем дискретное косинусное преобразование
        double[][] dctResult = applyDCT(pixels);

        // Записываем результат обратно в изображение
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                imageOut.setIntColor(x + i, y + j, (int) dctResult[i][j], (int) dctResult[i][j], (int) dctResult[i][j]);
            }
        }
    }

    private double[][] applyDCT(int[][] pixels) {
        int width = pixels.length;
        int height = pixels[0].length;

        double[][] result = new double[width][height];

        for (int u = 0; u < width; u++) {
            for (int v = 0; v < height; v++) {
                double sum = 0.0;

                for (int i = 0; i < width; i++) {
                    for (int j = 0; j < height; j++) {
                        sum += Math.cos((2.0 * i + 1.0) / (2.0 * width) * u * Math.PI) *
                                Math.cos((2.0 * j + 1.0) / (2.0 * height) * v * Math.PI) *
                                (pixels[i][j] - 128); // Предварительно вычитаем 128 для центрирования
                    }
                }

                double cu = (u == 0) ? 1.0 / Math.sqrt(2) : 1.0;
                double cv = (v == 0) ? 1.0 / Math.sqrt(2) : 1.0;

                result[u][v] = 0.25 * cu * cv * sum;
            }
        }

        return result;
    }

    @Override
    public MarvinAttributesPanel getAttributesPanel() {
        return null;
    }

    @Override
    public void process(MarvinImage marvinImage, MarvinImage marvinImage1, MarvinAttributes marvinAttributes, MarvinImageMask marvinImageMask, boolean b) {

    }

    @Override
    public void process(MarvinImage marvinImage, MarvinImage marvinImage1, MarvinImageMask marvinImageMask) {

    }

    @Override
    public void process(MarvinImage marvinImage, MarvinImage marvinImage1, MarvinAttributes marvinAttributes) {

    }

    @Override
    public void process(MarvinImage marvinImage, MarvinImage marvinImage1) {

    }

    @Override
    public void process(List<MarvinImage> list, MarvinImage marvinImage) {

    }

    @Override
    public void setImagePanel(MarvinImagePanel marvinImagePanel) {

    }

    @Override
    public MarvinImagePanel getImagePanel() {
        return null;
    }

    @Override
    public void load() {

    }

    @Override
    public void validate() {

    }

    @Override
    public void invalidate() {

    }

    @Override
    public boolean isValid() {
        return false;
    }

    @Override
    public MarvinAttributes getAttributes() {
        return null;
    }

    @Override
    public void setAttribute(String s, Object o) {

    }

    @Override
    public void setAttributes(Object... objects) {

    }

    @Override
    public Object getAttribute(String s) {
        return null;
    }
}

尝试使用 TwelveMonkeys 库,但它没有影响任何事情,只是让它变得更糟。希望能帮到你!

Java 哈希 项目 照片 phash

评论


答: 暂无答案