NSImage转opencv图像, opencv图像转NSImage

7 篇文章 1 订阅
NSImage *outImage;
NSImage *inputImage = [NSImage imageNamed:@"zhangsan.jpg"];
           int m_nWidth = inputImage.size.width;
           int m_nHeight = inputImage.size.height;
       
           //NSImage转cv图
           cv::Mat mat_pt = cv::Mat(m_nHeight, m_nWidth, CV_8UC4);
           memcpy(mat_pt.data, [inputImage RGBAData],
                  sizeof(unsigned char) * m_nWidth * m_nHeight * 4);
           //写在cv图上
           cv::Point point(10.0,10.0);
           float texSize = m_nWidth * m_nHeight *0.0000004;
           cv::putText(mat_pt, std::to_string(10), point,
                       cv::FONT_HERSHEY_DUPLEX, texSize, cv::Scalar(255, 0, 255), 2,
                       cv::LINE_AA);
           //cv图转NSImage
           unsigned char* tempData = new unsigned char[m_nWidth * m_nHeight * 4];
           memcpy(tempData, mat_pt.data,
                  sizeof(unsigned char) * m_nWidth * m_nHeight * 4);
           mat_pt.release();
          outImage = [NSImage imageWithRGBAData:tempData withWidth:m_nWidth withHeight:m_nHeight];
           [ self.m_imageView setImage:outImage];

其中,RGBAData

-(unsigned char*)RGBAData{
    //【1】NSImage创建CGImageRef
    struct CGImageSource *source=CGImageSourceCreateWithData((__bridge  CFDataRef)[self TIFFRepresentation],NULL);//创建从Core Foundation数据对象读取的图像源
    NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
                             (id)kCFBooleanFalse, (id)kCGImageSourceShouldCache,
                             (id)kCFBooleanTrue, (id)kCGImageSourceShouldAllowFloat,
                             nil];//创建字典
    CGImageRef imageRef =  CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)options);//为与图像源中指定索引关联的图像数据创建CGImage对象
    
    //【2】由CGImageRef创建CGContextRef
    CGContextRef context = NULL;//Quartz 2D绘图环境,图形上下文
    CGColorSpaceRef colorSpace;//指定如何解释显示的颜色值
    
    uint32_t *bitmapData1;//图像数据

    size_t bitsPerPixel = 32;//32位图
    size_t bitsPerComponent = 8;//8位,0-255
    size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;//4通道

    size_t width = CGImageGetWidth(imageRef);//以像素为单位,位图图像(或蒙版)的宽度
    size_t height = CGImageGetHeight(imageRef);//高度

    size_t bytesperRow = width * bytesPerPixel;
    size_t bufferLength = bytesperRow * height;

    //(1)分配设备颜色空间
    colorSpace = CGColorSpaceCreateDeviceRGB();
    if(!colorSpace) {
        NSLog(@"Error allocating color space RGB\n");//颜色空间没有分配成功
        return NULL;
    }
    
    //(2)为image data分配内存
    bitmapData1 = (uint32_t *)malloc(bufferLength);
    if(!bitmapData1) {
        NSLog(@"Error allocating memory for bitmap\n");
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }
    //(3)创建bitmap 的上下文context
    context=CGBitmapContextCreate(bitmapData1,
                                  width,
                                  height,
                                  bitsPerComponent,
                                  bytesperRow,
                                  colorSpace,
                                  kCGImageAlphaPremultipliedLast);//RGBA
    if(!context) {
        free(bitmapData1);
        NSLog(@"picProcessing::newBitmapRGBA8ContextFromImage:Bitmap context not created");
    }
    CGColorSpaceRelease(colorSpace);//释放颜色空间
    //(4)获取CGImageRef的宽高,并将CGImageRef画到CGContextRef中,以获取rawdata
    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);//将当前的填充颜色设置为DeviceRGB颜色空间中的值
    CGContextFillRect(context, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height));//使用当前图形状态下的填充颜色绘制提供的矩形中包含的区域
    
    unsigned long imageWidth = CGImageGetWidth(imageRef);
    unsigned long imageHeight = CGImageGetHeight(imageRef);
    CGRect imgRect = CGRectMake(0, 0, imageWidth, imageHeight);
    CGContextDrawImage(context, imgRect, imageRef);//将图像绘制到图形上下文中。
    
    unsigned char * bitmapData = (unsigned char * )CGBitmapContextGetData(context);//(5)获取CGContextRef中的rawdata的指针

    unsigned char array[256][256] = {0};
    for (int j=1; j<256; j++)
    {
        for (int i=0; i<256; i++)
        {
            array[j][i] = fmin(fmax(0.0f,(j+i-255)*255.0/i+0.5),255.0f);
        }
    }
    GLubyte* alphaData = (GLubyte*) calloc(width * height, sizeof(GLubyte));
    CGContextRef alphaContext = CGBitmapContextCreate(alphaData, width, height, 8, width, NULL, kCGImageAlphaOnly);
    CGContextDrawImage(alphaContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), imageRef);
    //(5)将image的数据绘制进bitmap context
    CGContextRelease(alphaContext);
    GLubyte* pDest = bitmapData;
    GLubyte* alphaTemp = alphaData;
    for (int j=0; j<height; j++)
    {
        for (int i=0; i<width; i++)
        {

            //自己反计算回原来的alpha值
            pDest[0] = array[pDest[0]][alphaTemp[0]];
            pDest[1] = array[pDest[1]][alphaTemp[0]];
            pDest[2] = array[pDest[2]][alphaTemp[0]];

            pDest[3] = alphaTemp[0];
            pDest += 4;
            alphaTemp++;
        }
    }
    free(alphaData);

    return bitmapData;
}

其中,imageWithRGBAData

+ (NSImage*) imageWithRGBAData:(unsigned char*)data withWidth:(int) width withHeight:(int) height{
    //根据bitmap指针创建CGContextRef
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, width * height * 4, NULL);
    size_t bitsPerComponent = 8;
    size_t bitsPerPixel = 32;
    //size_t bytesPerRow = 4 * imageWidth;
    
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    if(colorSpaceRef == NULL) {
        NSLog(@"Error allocating color space");
        CGDataProviderRelease(provider);
    }
    
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    
    CGImageRef iref = CGImageCreate(width,
                                    height,
                                    bitsPerComponent,
                                    bitsPerPixel,
                                    width * 4,
                                    colorSpaceRef,
                                    bitmapInfo,
                                    provider,    // data provider
                                    NULL,        // decode
                                    YES,            // should interpolate
                                    renderingIntent);
    
    uint32_t* pixels = (uint32_t*)malloc(width * height * 4);
    
    if(pixels == NULL) {
        NSLog(@"Error: Memory not allocated for bitmap");
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpaceRef);
        CGImageRelease(iref);
    }
    
    CGContextRef context = CGBitmapContextCreate(pixels,
                                                 width,
                                                 height,
                                                 bitsPerComponent,
                                                 width * 4,
                                                 colorSpaceRef,
                                                 bitmapInfo);
    
    if(context == NULL) {
        NSLog(@"Error context not created");
        free(pixels);
    }
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);
    
    // 根据这个位图context中的像素数据创建一个Quartz image对象
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    
    // 用Quartz image创建一个NSImage对象image
    CGSize size = CGSizeMake(width, height);
    NSImage *image = [[NSImage alloc]  initWithCGImage:quartzImage size:size];
    
    return image;
}
NSImage保存时,尺寸变大的原因可能有以下几点: 1. 原始图像的分辨率较低: 如果原始图像的分辨率较低,在保存时会根据保存格式的要求进行图像的重新采样和调整,从而导致图像的尺寸变大。保存时可以选择调整分辨率或使用更高的压缩比例来减小图像尺寸。 2. 使用了不支持无损压缩的图像格式: 某些图像格式,如JPEG,采用有损压缩,保存时会丢失一定的细节信息。如果原始图像是使用无损压缩的格式保存的,如PNG或TIFF,换成不支持无损压缩的格式时,可能会导致尺寸的增大。 3. 存储格式选择不合适: 不同的图像格式适用于不同的应用场景,选择不合适的存储格式可能导致图像尺寸变大。例如,某些压缩算法在保存图像时会引入更多的噪点或压缩伪影,从而增加了图像的尺寸。 解决这个问题的方法有以下几种: 1. 调整图像分辨率: 可以在保存图像之前,根据实际需求调整图像的分辨率,减小图像的尺寸。可以使用NSImage的scale方法来改变图像的大小,从而减小图像的分辨率。 2. 使用支持无损压缩的图像格式: 对于不希望丢失图像细节的情况,可以选择使用支持无损压缩的图像格式,如PNG或TIFF,来保存图像。 3. 选择合适的图像存储格式: 针对不同的应用场景,选择合适的图像存储格式可以减小图像尺寸并保持图像质量。例如,对于需要高质量、无损压缩的情况,可以选择使用TIFF格式保存图像。对于需要较小尺寸的情况,可以选择使用JPEG格式,根据需求调整压缩比例。 通过上述方法进行图像保存时,可以有效控制图像尺寸的大小,满足不同应用场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值