前言
首先安裝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的現象基本一致,但圖片的顯示速度要高於前者。
後記:圖片的相似度對比,識別,盲水印等等都是圖片的高級應用。我也在學習中。