libvips图像处理库运行速度快,并且占用的内存很少。 libvips是根据LGPL 2.1+授权的。(https://github.com/libvips/libvips)它具有约300种运算,涵盖算术,直方图,卷积,形态运算,频率滤波,颜色,重采样,统计等。虽然相比opencv等专业的库差了一些,但是其不占内存的特点,使其适合处理较大的图片。
NetVips 是libvips的.net封装,NetVips速度快,几乎不需要内存。 NetVips.Benchmarks项目针对Magick.NET和ImageSharp测试NetVips。 NetVips比Magick.NET快14倍,比ImageSharp快5倍。(https://kleisauke.github.io/net-vips/)
在windows项目使用还是比较方便的。nuget搜索NetVips,安装下面3个包即可。NetVips / NetVips.Native.win-x64 / NetVips.Native.win-x86
一、占用内存分析
看libvips的源码内,对于内存的处理部分,在mapfile.c中,有创建mmap,所以分析占用内存较少,但是在使用的时候会写入硬盘。
void *
vips__mmap( int fd, int writeable, size_t length, gint64 offset )
{
void *baseaddr;
#ifdef DEBUG
printf( "vips__mmap: length = 0x%zx, offset = 0x%lx\n",
length, offset );
#endif /*DEBUG*/
#ifdef OS_WIN32
{
HANDLE hFile = (HANDLE) _get_osfhandle( fd );
DWORD flProtect;
DWORD dwDesiredAccess;
HANDLE hMMFile;
ULARGE_INTEGER quad;
DWORD dwFileOffsetHigh;
DWORD dwFileOffsetLow;
if( writeable ) {
flProtect = PAGE_READWRITE;
dwDesiredAccess = FILE_MAP_WRITE;
}
else {
flProtect = PAGE_READONLY;
dwDesiredAccess = FILE_MAP_READ;
}
quad.QuadPart = offset;
dwFileOffsetLow = quad.LowPart;
dwFileOffsetHigh = quad.HighPart;
if( !(hMMFile = CreateFileMapping( hFile,
NULL, flProtect, 0, 0, NULL )) ) {
vips_error_system( GetLastError(), "vips_mapfile",
"%s", _( "unable to CreateFileMapping" ) );
printf( "CreateFileMapping failed: %s\n", vips_error_buffer() );
return( NULL );
}
if( !(baseaddr = (char *)MapViewOfFile( hMMFile, dwDesiredAccess,
dwFileOffsetHigh, dwFileOffsetLow, length )) ) {
vips_error_system( GetLastError(), "vips_mapfile",
"%s", _( "unable to MapViewOfFile" ) );
printf( "MapViewOfFile failed: %s\n", vips_error_buffer() );
CloseHandle( hMMFile );
return( NULL );
}
/* Can close mapping now ... view stays until UnmapViewOfFile().
FIXME ... is this a performance problem?
*/
CloseHandle( hMMFile );
}
#else /*!OS_WIN32*/
{
int prot;
int flags;
if( writeable )
prot = PROT_WRITE;
else
prot = PROT_READ;
flags = MAP_SHARED;
/* OS X caches mmapped files very aggressively if this flags is not
* set. Scanning a large file without this flag will cause every other
* process to get swapped out and kill performance.
*/
#ifdef MAP_NOCACHE
flags |= MAP_NOCACHE;
#endif /*MAP_NOCACHE*/
/* Casting gint64 to off_t should be safe, even on *nixes without
* LARGEFILE.
*/
baseaddr = mmap( 0, length, prot, flags, fd, (off_t) offset );
if( baseaddr == MAP_FAILED ) {
vips_error_system( errno, "vips_mapfile",
"%s", _( "unable to mmap" ) );
g_warning( _( "map failed (%s), "
"running very low on system resources, "
"expect a crash soon" ), strerror( errno ) );
return( NULL );
}
}
#endif /*OS_WIN32*/
return( baseaddr );
}
二、简单使用
通道分割
NetVips.Image image = NetVips.Image.NewFromFile("C:\\Users\\xiaomao\\Desktop\\1.jpg", memory: false, access: Enums.Access.Random);
NetVips.Image[] images = image.Bandsplit();
水平镜像
NetVips.Image image = NetVips.Image.NewFromFile("C:\\Users\\xiaomao\\Desktop\\1.jpg", memory: false, access: Enums.Access.Random);
NetVips.Image gauss = image.Flip(NetVips.Enums.Direction.Horizontal);
高斯滤波
NetVips.Image image = NetVips.Image.NewFromFile("C:\\Users\\xiaomao\\Desktop\\1.jpg", memory: false, access: Enums.Access.Random);
NetVips.Image gauss = image.Gaussblur(15);
图像旋转
NetVips.Image image = NetVips.Image.NewFromFile("C:\\Users\\xiaomao\\Desktop\\2.jpg", memory: false, access: Enums.Access.Random);
NetVips.Image gauss = image.Rot90();
Canny/Sobel边缘检测
NetVips.Image image = NetVips.Image.NewFromFile("C:\\Users\\xiaomao\\Desktop\\1.jpg", memory: false, access: Enums.Access.Random);
NetVips.Image canny= image.Canny(1.8, Enums.Precision.Float);
NetVips.Image sobel = image.Sobel();