Search code examples
imageffmpegjpegmjpeg

JPEG quality problems


I am currently using C# to retrieve frames from a borescope (via the FFMPEG library). However, I came across a problem weeks ago and I can't solve it.

The images are returned in JPEG format (since the borescope stream is MJPEG).

Some images come without quality problems, but others come with a strange line in the middle followed by random staining. (At the end of the question there is an example of a normal image and one with problems).

Analyzing the structure of the files, I realized that there are some differences, but I don't really understand JPEG's binary structure very well, and I can't tell what is corrupted.

Getting to know what is corrupted in the image, which culminates in the quality problem, is very important to me because, through this, I can discard the frame using C#. However, without understanding this problem, I can't even discard the frame, much less fix it.

So, having the image without quality problems as a reference, what is the problem with the binary structure of the image with quality problems?

Examples:

JPEG 1: Image without quality problems

Image's preview (just to see the quality, do not download from here)

JPEG 2: Image with quality problems

Image's preview (just to see the quality, do not download from here)

It's possible to look into binary structure of images through online HEX editors like: Online hex editor, Hexed or Hex-works.

Thank you for reading and have a nice day.


Solution

  • There are at least 2 issues with the file.


    The first I can detect with ImageMagick by running this command:

    magick identify -verbose image.jpg
    

    and it tells me that the data segment ends prematurely.

    Image: outExemplo0169.jpeg
      Format: JPEG (Joint Photographic Experts Group JFIF format)
      Mime type: image/jpeg
      Class: DirectClass
      Geometry: 640x480+0+0
      Units: Undefined
      Colorspace: sRGB
      Type: TrueColor
      Base type: Undefined
      Endianess: Undefined
      Depth: 8-bit
      Channel depth:
        Red: 8-bit
        Green: 8-bit
        Blue: 8-bit
      Channel statistics:
        Pixels: 307200
        Red:
          min: 0  (0)
          max: 255 (1)
          mean: 107.234 (0.420527)
          standard deviation: 66.7721 (0.261851)
          kurtosis: -0.67934
          skewness: 0.577494
          entropy: 0.92876
        Green:
          min: 0  (0)
    :2020-02-26T18:59:19+00:00 0:00.057 0.070u 7.0.9 Resource identify[80956]: resource.c/RelinquishMagickResource/1067/Resource
      Memory: 3686400B/0B/32GiB
    identify: Corrupt JPEG data: premature end of data segment `outExemplo0169.jpeg' @ warning/jpeg.c/JPEGWarningHandler/399.
    

    The second I can see with exiftool when I run this command:

    exiftool -v -v -v outExemplo0169.jpeg 
    
      ExifToolVersion = 11.11
      FileName = outExemplo0169.jpeg
      Directory = .
      FileSize = 66214
      FileModifyDate = 1582743337
      FileAccessDate = 1582743559
      FileInodeChangeDate = 1582743337
      FilePermissions = 33188
      FileType = JPEG
      FileTypeExtension = JPG
      MIMEType = image/jpeg
    JPEG APP0 (14 bytes):
        0006: 4a 46 49 46 00 01 01 00 00 01 00 01 00 00       [JFIF..........]
      + [BinaryData directory, 9 bytes]
      | JFIFVersion = 1 1
      | - Tag 0x0000 (2 bytes, int8u[2]):
      |     000b: 01 01                                           [..]
      | ResolutionUnit = 0
      | - Tag 0x0002 (1 bytes, int8u[1]):
      |     000d: 00                                              [.]
      | XResolution = 1
      | - Tag 0x0003 (2 bytes, int16u[1]):
      |     000e: 00 01                                           [..]
      | YResolution = 1
      | - Tag 0x0005 (2 bytes, int16u[1]):
      |     0010: 00 01                                           [..]
      | ThumbnailWidth = 0
      | - Tag 0x0007 (1 bytes, int8u[1]):
      |     0012: 00                                              [.]
      | ThumbnailHeight = 0
      | - Tag 0x0008 (1 bytes, int8u[1]):
      |     0013: 00                                              [.]
    JPEG SOF0 (15 bytes):
        0018: 08 01 e0 02 80 03 01 21 00 02 11 01 03 11 01    [.......!.......]
      ImageWidth = 640
      ImageHeight = 480
      EncodingProcess = 0
      BitsPerSample = 8
      ColorComponents = 3
    JPEG DQT (130 bytes):
        002b: 00 03 03 03 03 03 03 04 03 03 03 04 04 04 05 06 [................]
        003b: 09 06 06 05 05 06 0c 08 09 07 09 0e 0c 0e 0e 0d [................]
        004b: 0c 0d 0d 0f 11 15 12 0f 10 14 10 0d 0d 13 19 13 [................]
        005b: 14 16 17 18 18 18 0f 12 1a 1c 1a 17 1c 15 17 18 [................]
        006b: 17 01 04 04 04 06 05 06 0b 06 06 0b 17 0f 0d 0f [................]
        007b: 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 [................]
        008b: 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 [................]
        [snip 18 bytes]
    JPEG DHT (416 bytes):
        00b1: 00 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 [................]
        00c1: 00 00 01 02 03 04 05 06 07 08 09 0a 0b 10 00 02 [................]
        00d1: 01 03 03 02 04 03 05 05 04 04 00 00 01 7d 01 02 [.............}..]
        00e1: 03 00 04 11 05 12 21 31 41 06 13 51 61 07 22 71 [......!1A..Qa."q]
        00f1: 14 32 81 91 a1 08 23 42 b1 c1 15 52 d1 f0 24 33 [.2....#B...R..$3]
        0101: 62 72 82 09 0a 16 17 18 19 1a 25 26 27 28 29 2a [br........%&'()*]
        0111: 34 35 36 37 38 39 3a 43 44 45 46 47 48 49 4a 53 [456789:CDEFGHIJS]
        [snip 304 bytes]
    JPEG SOS
    JPEG EOI
    Unknown trailer (50 bytes at offset 0x10274):
       10274: 42 6f 75 6e 64 61 72 79 45 42 6f 75 6e 64 61 72 [BoundaryEBoundar]
       10284: 79 53 00 00 01 00 90 08 01 00 fb 4b db 6a 2a 22 [yS.........K.j*"]
       10294: 00 00 2a 22 00 00 01 00 01 00 80 02 00 00 e0 01 [..*"............]
       102a4: 00 00        
    

    So there are 50 extraneous bytes at the end including the text string "BoundaryEBoundaryS" which may be recognisable to you as coming from somewhere else in your processing chain?

    One test you could do for JPEG quality is check the last 2 bytes are a valid EOI which means it should end in FF D9 - see here.