dlemstra / Magick.NET

The .NET library for ImageMagick
Apache License 2.0
3.32k stars 406 forks source link

Change in image quality after performing EXIF operation #1488

Open sumedhvidhate opened 6 months ago

sumedhvidhate commented 6 months ago

Magick.NET version

13.4.0

Environment (Operating system, version and so on)

Windows

Description

When performing EXIF operation on the image, image properties are getting changed. On carrying out pixel by pixel comparison it was found out that there was around 50% pixels changed even after using the commands - image.Quality = 100; image.Settings.Compression = CompressionMethod.NoCompression;

We are using this images for photogrammetry purpose and ortho-mosaic generation. There is significant change in the size too after performing EXIF operation

Here I'm attaching the images in the drive link below https://drive.google.com/drive/folders/1ggSsa2eM1IS-fDxVTuHK8P5P6_i3XCnB?usp=drive_link

The code I'm using is as follows

    XmpMetaFactory.SchemaRegistry.RegisterNamespace("http://www.pix4d.com", "Camera");

    try
    {
        using (MagickImage image = new MagickImage(_imagePath))
        {

            #region Add EXIF metadata

            IExifProfile exifProfile = image.GetExifProfile();
            if (exifProfile == null)
            {
                exifProfile = new ExifProfile();
            }

            exifProfile.SetValue(ExifTag.GPSLatitudeRef, _latitude >= 0 ? "N" : "S"); // select between northern (N) / southern (S) hemisphere
            var data = ConvertToRationalDMS(Math.Abs(_latitude));
            exifProfile.SetValue(ExifTag.GPSLatitude, data);

            data = ConvertToRationalDMS(Math.Abs(_longitude));
            exifProfile.SetValue(ExifTag.GPSLongitudeRef, _longitude >= 0 ? "E" : "W"); // select between eastern (E) / western (W) hemisphere
            exifProfile.SetValue(ExifTag.GPSLongitude, data);

            exifProfile.SetValue(ExifTag.GPSAltitudeRef, _altitude >= 0 ? (byte)0 : (byte)1); // select between above (0) / below (1)  sea-level
            exifProfile.SetValue(ExifTag.GPSAltitude, new Rational(Math.Abs(_altitude)));

            image.SetProfile(exifProfile);

            #endregion

            #region Add XMP metadata

            IXmpProfile xmpProfile1 = image.GetXmpProfile();

            Console.WriteLine();

            IXmpMeta xmpData = XmpMetaFactory.Create();

            xmpData.SetProperty("http://www.pix4d.com", "GPSXAccuracy", $"{_gpsXAccuracy:0.0000000000}");
            xmpData.SetProperty("http://www.pix4d.com", "GPSYAccuracy", $"{_gpsYAccuracy:0.0000000000}");
            xmpData.SetProperty("http://www.pix4d.com", "GPSZAccuracy", $"{_gpsZAccuracy:0.0000000000}");
            xmpData.SetProperty("http://www.pix4d.com", "GPSXYAccuracy", $"{_gpsXYAccuracy:0.0000000000}");
            xmpData.SetProperty("http://www.pix4d.com", "RINEXTimestamp", $"{_eventTime:yyyyMMdd_HHmmss.fff}");

            string serializedData = XmpMetaFactory.SerializeToString(xmpData, new XmpCore.Options.SerializeOptions());
            IXmpProfile xmpProfile = new XmpProfile(System.Text.Encoding.UTF8.GetBytes(serializedData));

            image.SetProfile(xmpProfile);

            #endregion
            image.Interlace = Interlace.NoInterlace;
            image.Quality = 100;
            image.Settings.Compression = CompressionMethod.NoCompression;
            var optimizer = new ImageOptimizer();
            optimizer.LosslessCompress(_imagePath);

            image.Write(_newImagePath);
        }
    }
    catch (Exception exp)
    {
    }

}

Steps to Reproduce

I have uploaded both the raw image and the EXIF image, processed using ImageMagick, to the drive link.

dlemstra commented 6 months ago

When you read/write a JPG image the pixels will change because the format is losses. But in your case the difference is very small:

compare -metric rmse "raw image.JPG" ImageMagick_exif.JPG null:
91.6095 (0.00139787)

The pixels are only 0.00139787 different. The size is larger because you are using a quality of 100 instead of 95. If you only want to change the metadata of the image you probably don't want to use this library because it also decodes and encodes the pixels causing them to change slightly.