關於圖片的一些知識

前言

首先安裝MediaInfo Command line, 

MediaInfoLib - v19.04

Usage: "mediainfo [-Options...] FileName1 [Filename2...]"

這個工具對圖片、視頻的屬性讀取非常全面。對音視頻圖片等多媒體進行開發的時候是一個非常好的輔助工具。

示例:

這裏可以知道圖片的一些重要屬性
格式:PNG
壓縮算法:LZ77 (目前主流的無損數據壓縮算法,https://zh.wikipedia.org/wiki/LZ77%E4%B8%8ELZ78)
寬度:825px
高度:525px
位深度:24bits (位深度爲每個像素點可以支持顯示的顏色數量,單位是bits,本圖片可以顯示2 ^ 24 = 16,777,216個顏色)
文件大小:419kb

圖片在內存中的佔用

圖片顯示在屏幕上時,其實是一種解碼解壓的過程,將圖片放入內存中,然後再顯示。

我們使用圖片處理開源框架ImageMagick。採用C++編寫,可以用來讀、寫和處理超過90種的圖片文件,等有時間我發一個通過ImageMagick的離散傅里葉變換來實現磨皮降噪等效果的文章,當然openCV也可以,讓技術變得簡單了好多,傅里葉變換在多媒體處理上是很神奇的原理。

上面示例圖片的大小是419kb,那麼放入內存中佔用的內存大小是多少呢?這個計算方式爲:

imgWidth * imgHeight * (bit depth) / 8 = 825 * 525 * 24 / 8 = 1299375 字節

可以通過ImageMagick來驗證一下是否正確,代碼如下:

#include <iostream>
#include <fstream>
#include "Magick++.h"

using namespace Magick;
using namespace std;

int main(int argc, char** argv)
{
    Image image;
    try
    {
        InitializeMagick(*argv);
        image.read(argv[1]); //第一個參數是圖片路徑
        PixelData pxlsDat(image, argv[2], MagickCore::CharPixel); // 第二個參數是ColorSpace
        cout << " Bit depth is " << image.depth() << ", memory use is " << pxlsDat.size() << endl;
    }
    catch (Magick::Exception &error_)
    {
        cout << "Caught exception: " << error_.what() << endl; 
        return 1;
    }
    return 0;
}

關於第二個參數,其實可以通過identify -list format來查看支持的所有格式,如果查看圖片的ColorSpace就使用
identify -verbose /path/to/image

我們可以查到上述圖片Colorspace: sRGB

編譯代碼:

CXX = g++
CXXFLAGS = `Magick++-config --cxxflags --cppflags` -O2 -Wall
LIBS=`Magick++-config --ldflags --libs`
SRC = readImage.cpp
OBJFILES = readImage.o
TARGET = readImage

all: $(TARGET)
    @echo $(TARGET) build finished.
$(TARGET): $(OBJFILES)
    $(CXX) $(CXXFLAGS) -o $(TARGET) $(SRC) $(LIBS) 
clean:
    rm -f $(OBJFILES) $(TARGET) *~

運行./readImage /path/to/image "rgb"
Output:Bit depth is 8, memory use is 1299375

與我們之前計算的一樣。419kb的圖片內存佔用1.2mb左右

引申:iOS對於大圖片讀取並顯示的方法

iOS的framework對多媒體的API絕對要超級友好於Android,例如對視頻的AVFoundation,CoreImage, vImage, CGImage, UIkit的圖片處理轉換等等,那是相當的豐富。

比如UIImage顯示圖片

- (void)showImageWithHardCore

{

    UIImage* tmpImage = [UIImage imageNamed:@"[email protected]"];

    _imgView.image = tmpImage;

}

圖片使用一個170多MB的png,寬高都是1w多px的,結果Virtual Memory直接飆升至990多MB.

我們首先需要將圖片的尺寸Downsampling到適合屏幕顯示的圖片,我們draw一下。

- (UIImage *)downsizeImage:(CGSize)size

{

    UIGraphicsBeginImageContextWithOptions(size, true, 1.0);

    [self drawInRect:CGRectMake(0, 0, size.width, size.height)];

    UIImage *downSizeImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return downSizeImage;

}

內存飆升後立即下降至40mb。

最後我們使用CGImage,這個方法也是蘋果官方推薦的做法:

- (UIImage *)downsizeImage:(NSURL*)url toSize:(CGSize)size scale:(CGFloat)scale

{

    NSDictionary *imageSourceOptions = @{(id)kCGImageSourceShouldCache : @(NO)};

    CGImageSourceRef imageSourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)url, (__bridge CFDictionaryRef)imageSourceOptions);

    CGFloat maxDimensionInPixels = MAX(size.width, size.height) * scale;

    NSDictionary *downSizeOptions = @{(id)kCGImageSourceCreateThumbnailFromImageAlways : @(YES),

                                      (id)kCGImageSourceShouldCacheImmediately : @(YES),

                                      (id)kCGImageSourceCreateThumbnailWithTransform : @(YES),

                                      (id)kCGImageSourceThumbnailMaxPixelSize : @(maxDimensionInPixels)

                                      };

    CGImageRef downSizeImageRef = CGImageSourceCreateThumbnailAtIndex(imageSourceRef, 0, (__bridge CFDictionaryRef)downSizeOptions);

    UIImage *returnImage = [UIImage imageWithCGImage:downSizeImageRef];

    CGImageRelease(downSizeImageRef);

    CFRelease(imageSourceRef);

    return returnImage;

}

內存佔用情況和drawrect的現象基本一致,但圖片的顯示速度要高於前者。

後記:圖片的相似度對比,識別,盲水印等等都是圖片的高級應用。我也在學習中。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章