Merge pull request #18547 from mtfrctl:objc-conversions-macosx

Mat conversions for macOS/AppKit

* Extract CoreGraphics conversion logics from ios_conversions.mm to apple_conversions.h, apple_conversions. Add macosx_conversions.mm

* Add macosx.h

* Add Mat+Conversions.h and Mat+Conversions.mm

* Delete duplicated declaration from apple_conversion.mm

* Use short license header

* Add compile guard

* Delete unused imports

* Move precomp.hpp import from header to implementation

* Add macosx.h to skip headers

* Fix compile guard condition

* Use short license header

* Remove commented out unused code
pull/18598/head
mtfrctl 4 years ago committed by GitHub
parent 4c048a487e
commit 7de189114b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      cmake/templates/opencv_abi.xml.in
  2. 8
      modules/imgcodecs/CMakeLists.txt
  3. 1
      modules/imgcodecs/include/opencv2/imgcodecs.hpp
  4. 20
      modules/imgcodecs/include/opencv2/imgcodecs/macosx.h
  5. 32
      modules/imgcodecs/misc/objc/macosx/Mat+Converters.h
  6. 44
      modules/imgcodecs/misc/objc/macosx/Mat+Converters.mm
  7. 11
      modules/imgcodecs/src/apple_conversions.h
  8. 94
      modules/imgcodecs/src/apple_conversions.mm
  9. 96
      modules/imgcodecs/src/ios_conversions.mm
  10. 25
      modules/imgcodecs/src/macosx_conversions.mm
  11. 5
      modules/objc/generator/gen_objc.py

@ -32,6 +32,7 @@
opencv2/flann/hdf5.h
opencv2/imgcodecs/imgcodecs_c.h
opencv2/imgcodecs/ios.h
opencv2/imgcodecs/macosx.h
opencv2/videoio/videoio_c.h
opencv2/videoio/cap_ios.h
opencv2/xobjdetect/private.hpp

@ -113,10 +113,18 @@ file(GLOB imgcodecs_ext_hdrs
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/legacy/*.h"
)
if(APPLE)
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/apple_conversions.h)
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/apple_conversions.mm)
endif()
if(IOS)
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/ios_conversions.mm)
list(APPEND IMGCODECS_LIBRARIES "-framework UIKit" "-framework AssetsLibrary")
endif()
if(APPLE AND (NOT IOS))
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/macosx_conversions.mm)
list(APPEND IMGCODECS_LIBRARIES "-framework AppKit")
endif()
if(APPLE_FRAMEWORK)
list(APPEND IMGCODECS_LIBRARIES "-framework Accelerate" "-framework CoreGraphics" "-framework QuartzCore")
endif()

@ -50,6 +50,7 @@
@{
@defgroup imgcodecs_c C API
@defgroup imgcodecs_ios iOS glue
@defgroup imgcodecs_macosx MacOS(OSX) glue
@}
*/

@ -0,0 +1,20 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#if !defined(__APPLE__) || !defined(__MACH__)
#error This header should be used in macOS ObjC/Swift projects.
#endif
#import <AppKit/AppKit.h>
#include "opencv2/core.hpp"
//! @addtogroup imgcodecs_macosx
//! @{
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image);
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist = false);
CV_EXPORTS NSImage* MatToNSImage(const cv::Mat& image);
CV_EXPORTS void NSImageToMat(const NSImage* image, cv::Mat& m, bool alphaExist = false);
//! @}

@ -0,0 +1,32 @@
//
// Mat+Converters.h
//
// Created by Masaya Tsuruta on 2020/10/08.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#else
#define CV_EXPORTS
#endif
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
CV_EXPORTS @interface Mat (Converters)
-(CGImageRef)toCGImage;
-(instancetype)initWithCGImage:(CGImageRef)image;
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist;
-(NSImage*)toNSImage;
-(instancetype)initWithNSImage:(NSImage*)image;
-(instancetype)initWithNSImage:(NSImage*)image alphaExist:(BOOL)alphaExist;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,44 @@
//
// Mat+Converters.mm
//
// Created by Masaya Tsuruta on 2020/10/08.
//
#import "Mat+Converters.h"
#import <opencv2/imgcodecs/macosx.h>
@implementation Mat (Converters)
-(CGImageRef)toCGImage {
return MatToCGImage(self.nativeRef);
}
-(instancetype)initWithCGImage:(CGImageRef)image {
return [self initWithCGImage:image alphaExist:NO];
}
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist {
self = [self init];
if (self) {
CGImageToMat(image, self.nativeRef, (bool)alphaExist);
}
return self;
}
-(NSImage*)toNSImage {
return MatToNSImage(self.nativeRef);
}
-(instancetype)initWithNSImage:(NSImage*)image {
return [self initWithNSImage:image alphaExist:NO];
}
-(instancetype)initWithNSImage:(NSImage*)image alphaExist:(BOOL)alphaExist {
self = [self init];
if (self) {
NSImageToMat(image, self.nativeRef, (bool)alphaExist);
}
return self;
}
@end

@ -0,0 +1,11 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#import <Accelerate/Accelerate.h>
#import <AVFoundation/AVFoundation.h>
#import <ImageIO/ImageIO.h>
#include "opencv2/core.hpp"
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image);
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist);

@ -0,0 +1,94 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "apple_conversions.h"
#include "precomp.hpp"
CGImageRef MatToCGImage(const cv::Mat& image) {
NSData *data = [NSData dataWithBytes:image.data
length:image.step.p[0] * image.rows];
CGColorSpaceRef colorSpace;
if (image.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider =
CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// Preserve alpha transparency, if exists
bool alpha = image.channels() == 4;
CGBitmapInfo bitmapInfo = (alpha ? kCGImageAlphaLast : kCGImageAlphaNone) | kCGBitmapByteOrderDefault;
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(image.cols,
image.rows,
8 * image.elemSize1(),
8 * image.elemSize(),
image.step.p[0],
colorSpace,
bitmapInfo,
provider,
NULL,
false,
kCGRenderingIntentDefault
);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return imageRef;
}
void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist) {
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image);
CGFloat cols = CGImageGetWidth(image), rows = CGImageGetHeight(image);
CGContextRef contextRef;
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelMonochrome)
{
m.create(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
bitmapInfo = kCGImageAlphaNone;
if (!alphaExist)
bitmapInfo = kCGImageAlphaNone;
else
m = cv::Scalar(0);
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
m.step[0], colorSpace,
bitmapInfo);
}
else if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelIndexed)
{
// CGBitmapContextCreate() does not support indexed color spaces.
colorSpace = CGColorSpaceCreateDeviceRGB();
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
if (!alphaExist)
bitmapInfo = kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault;
else
m = cv::Scalar(0);
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
m.step[0], colorSpace,
bitmapInfo);
CGColorSpaceRelease(colorSpace);
}
else
{
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
if (!alphaExist)
bitmapInfo = kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault;
else
m = cv::Scalar(0);
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
m.step[0], colorSpace,
bitmapInfo);
}
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows),
image);
CGContextRelease(contextRef);
}

@ -41,105 +41,23 @@
//M*/
#import <UIKit/UIKit.h>
#import <Accelerate/Accelerate.h>
#import <AVFoundation/AVFoundation.h>
#import <ImageIO/ImageIO.h>
#include "opencv2/core.hpp"
#include "precomp.hpp"
#include "apple_conversions.h"
CV_EXPORTS UIImage* MatToUIImage(const cv::Mat& image);
CV_EXPORTS void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist);
UIImage* MatToUIImage(const cv::Mat& image) {
NSData *data = [NSData dataWithBytes:image.data
length:image.step.p[0] * image.rows];
CGColorSpaceRef colorSpace;
if (image.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider =
CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// Preserve alpha transparency, if exists
bool alpha = image.channels() == 4;
CGBitmapInfo bitmapInfo = (alpha ? kCGImageAlphaLast : kCGImageAlphaNone) | kCGBitmapByteOrderDefault;
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(image.cols,
image.rows,
8 * image.elemSize1(),
8 * image.elemSize(),
image.step.p[0],
colorSpace,
bitmapInfo,
provider,
NULL,
false,
kCGRenderingIntentDefault
);
CGImageRef imageRef = MatToCGImage(image);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
UIImage *uiImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return finalImage;
return uiImage;
}
void UIImageToMat(const UIImage* image,
cv::Mat& m, bool alphaExist) {
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = CGImageGetWidth(image.CGImage), rows = CGImageGetHeight(image.CGImage);
CGContextRef contextRef;
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelMonochrome)
{
m.create(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
bitmapInfo = kCGImageAlphaNone;
if (!alphaExist)
bitmapInfo = kCGImageAlphaNone;
else
m = cv::Scalar(0);
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
m.step[0], colorSpace,
bitmapInfo);
}
else if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelIndexed)
{
// CGBitmapContextCreate() does not support indexed color spaces.
colorSpace = CGColorSpaceCreateDeviceRGB();
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
if (!alphaExist)
bitmapInfo = kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault;
else
m = cv::Scalar(0);
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
m.step[0], colorSpace,
bitmapInfo);
CGColorSpaceRelease(colorSpace);
}
else
{
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
if (!alphaExist)
bitmapInfo = kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault;
else
m = cv::Scalar(0);
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
m.step[0], colorSpace,
bitmapInfo);
}
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows),
image.CGImage);
CGContextRelease(contextRef);
void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist) {
CGImageRef imageRef = image.CGImage;
CGImageToMat(imageRef, m, alphaExist);
}

@ -0,0 +1,25 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#import <AppKit/AppKit.h>
#include "apple_conversions.h"
CV_EXPORTS NSImage* MatToNSImage(const cv::Mat& image);
CV_EXPORTS void NSImageToMat(const NSImage* image, cv::Mat& m, bool alphaExist);
NSImage* MatToNSImage(const cv::Mat& image) {
// Creating CGImage from cv::Mat
CGImageRef imageRef = MatToCGImage(image);
// Getting NSImage from CGImage
NSImage *nsImage = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef))];
CGImageRelease(imageRef);
return nsImage;
}
void NSImageToMat(const NSImage* image, cv::Mat& m, bool alphaExist) {
CGImageRef imageRef = [image CGImageForProposedRect:NULL context:NULL hints:NULL];
CGImageToMat(imageRef, m, alphaExist);
}

@ -1584,6 +1584,11 @@ if __name__ == "__main__":
if os.path.exists(ios_files_dir):
copied_files += copy_objc_files(ios_files_dir, objc_base_path, module, True)
if args.target == 'osx':
osx_files_dir = os.path.join(misc_location, 'macosx')
if os.path.exists(osx_files_dir):
copied_files += copy_objc_files(osx_files_dir, objc_base_path, module, True)
objc_test_files_dir = os.path.join(misc_location, 'test')
if os.path.exists(objc_test_files_dir):
copy_objc_files(objc_test_files_dir, objc_test_base_path, 'test', False)

Loading…
Cancel
Save