pythonimageopencvimage-processingrawimage

How to read a RAW image file format into OpenCV without any loss of resolution?


I am trying to import a Nikon '.NEF' file into OpenCV. '.NEF' is the file extension for a RAW file format for pictures captured by Nikon cameras. When I open the file in Preview on a Mac, I see that the resolution is 6000 by 4000, and the picture is extremely clear. However, when I import it into OpenCV, I see only 120 by 160 (by 3 for RGB channels) data points, and this leads to a big loss in resolution.

My understanding is that there are 120 by 160 pixels in the NumPy array storing the information about pixels for OpenCV. I tried using -1 for the IMREAD_UNCHANGED flag, but many pixels were left out and image quality was greatly affected.

For your reference, here is my code:

# first Jupyter block
img = cv2.imread('DSC_1051.NEF', -1)
img.shape

Performing img.shape returns (120, 160, 3).

# second Jupyter block
cv2.namedWindow("Resize", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Resize", 1000, 700)
  
# Displaying the image
cv2.imshow("Resize", img)

cv2.waitKey(0)
cv2.destroyAllWindows()

Summary of problem:

My question: how can I use OpenCV to import the desired number of pixels? Is there a specific function that I can use? Am I missing an argument to be passed?


Solution

  • If you want to manipulate RAW images without losing resolution with python you'd need to check on a specialized library like rawpy

    import rawpy
    
    with rawpy.imread('filename.NEF') as raw:
        raw_image = raw.raw_image
    

    You can check the rawpy documentation for more information

    Notes:

    Example 1: how to save .NEF as .jpg

    Option A: rawpy + Pillow (you need to install Pillow too)

    import rawpy
    from PIL import Image
    
    with rawpy.imread('filename.NEF') as raw:
        rgb = raw.postprocess(use_camera_wb=True)
        Image.fromarray(rgb).save('image.jpg', quality=90, optimize=True)
    

    Option B: rawpy + cv2

    import rawpy
    import cv2
    
    with rawpy.imread('filename.NEF') as raw:
        rgb = raw.postprocess(use_camera_wb=True)
        bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
        cv2.imwrite("image.jpg",bgr)
    

    Quality comparison

    I test the code with this 19.2mb .NEF image and I got these results:

    Method .jpg output size Dimensions
    PIL 9kb 320x212
    cv2 14kb 320x212
    rawpy + PIL 1.4mb 4284 × 2844
    rawpy + cv2 2.5mb 4284 × 2844

    Example 2: show .NEF with cv2

    import rawpy
    import cv2
    
    with rawpy.imread('filename.NEF') as raw:
        rgb = raw.postprocess(use_camera_wb=True)
        bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
    
        cv2.imshow('image', bgr)
        cv2.waitKey(0)
        cv2.destroyAllWindows()