mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
Merge branch 4.x
This commit is contained in:
@@ -256,18 +256,26 @@ CV_EXPORTS_W size_t imcount(const String& filename, int flags = IMREAD_ANYCOLOR)
|
||||
/** @brief Saves an image to a specified file.
|
||||
|
||||
The function imwrite saves the image to the specified file. The image format is chosen based on the
|
||||
filename extension (see cv::imread for the list of extensions). In general, only 8-bit
|
||||
filename extension (see cv::imread for the list of extensions). In general, only 8-bit unsigned (CV_8U)
|
||||
single-channel or 3-channel (with 'BGR' channel order) images
|
||||
can be saved using this function, with these exceptions:
|
||||
|
||||
- 16-bit unsigned (CV_16U) images can be saved in the case of PNG, JPEG 2000, and TIFF formats
|
||||
- 32-bit float (CV_32F) images can be saved in PFM, TIFF, OpenEXR, and Radiance HDR formats;
|
||||
3-channel (CV_32FC3) TIFF images will be saved using the LogLuv high dynamic range encoding
|
||||
(4 bytes per pixel)
|
||||
- PNG images with an alpha channel can be saved using this function. To do this, create
|
||||
8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels
|
||||
should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below).
|
||||
- Multiple images (vector of Mat) can be saved in TIFF format (see the code sample below).
|
||||
- With OpenEXR encoder, only 32-bit float (CV_32F) images can be saved.
|
||||
- 8-bit unsigned (CV_8U) images are not supported.
|
||||
- With Radiance HDR encoder, non 64-bit float (CV_64F) images can be saved.
|
||||
- All images will be converted to 32-bit float (CV_32F).
|
||||
- With JPEG 2000 encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- With PAM encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- With PNG encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- PNG images with an alpha channel can be saved using this function. To do this, create
|
||||
8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels
|
||||
should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below).
|
||||
- With PGM/PPM encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- With TIFF encoder, 8-bit unsigned (CV_8U), 16-bit unsigned (CV_16U),
|
||||
32-bit float (CV_32F) and 64-bit float (CV_64F) images can be saved.
|
||||
- Multiple images (vector of Mat) can be saved in TIFF format (see the code sample below).
|
||||
- 32-bit float 3-channel (CV_32FC3) TIFF images will be saved
|
||||
using the LogLuv high dynamic range encoding (4 bytes per pixel)
|
||||
|
||||
If the image format is not supported, the image will be converted to 8-bit unsigned (CV_8U) and saved that way.
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Mat+Converters.h
|
||||
//
|
||||
// Created by Giles Payne on 2020/03/03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#import "opencv2/core.hpp"
|
||||
#else
|
||||
#define CV_EXPORTS
|
||||
#endif
|
||||
|
||||
#import "Mat.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface Mat (Converters)
|
||||
|
||||
-(CGImageRef)toCGImage CF_RETURNS_RETAINED;
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image;
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist;
|
||||
-(UIImage*)toUIImage;
|
||||
-(instancetype)initWithUIImage:(UIImage*)image;
|
||||
-(instancetype)initWithUIImage:(UIImage*)image alphaExist:(BOOL)alphaExist;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// Mat+Converters.mm
|
||||
//
|
||||
// Created by Giles Payne on 2020/03/03.
|
||||
//
|
||||
|
||||
#import "Mat+Converters.h"
|
||||
#import <opencv2/imgcodecs/ios.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;
|
||||
}
|
||||
|
||||
-(UIImage*)toUIImage {
|
||||
return MatToUIImage(self.nativeRef);
|
||||
}
|
||||
|
||||
-(instancetype)initWithUIImage:(UIImage*)image {
|
||||
return [self initWithUIImage:image alphaExist:NO];
|
||||
}
|
||||
|
||||
-(instancetype)initWithUIImage:(UIImage*)image alphaExist:(BOOL)alphaExist {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
UIImageToMat(image, self.nativeRef, (bool)alphaExist);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// MatConverters.h
|
||||
//
|
||||
// Created by Giles Payne on 2020/03/03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#import "opencv2/core.hpp"
|
||||
#else
|
||||
#define CV_EXPORTS
|
||||
#endif
|
||||
|
||||
#import "Mat.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface MatConverters : NSObject
|
||||
|
||||
+(CGImageRef)convertMatToCGImageRef:(Mat*)mat CF_RETURNS_RETAINED;
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image;
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image alphaExist:(BOOL)alphaExist;
|
||||
+(UIImage*)converMatToUIImage:(Mat*)mat;
|
||||
+(Mat*)convertUIImageToMat:(UIImage*)image;
|
||||
+(Mat*)convertUIImageToMat:(UIImage*)image alphaExist:(BOOL)alphaExist;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// MatConverters.mm
|
||||
//
|
||||
// Created by Giles Payne on 2020/03/03.
|
||||
//
|
||||
|
||||
#import "MatConverters.h"
|
||||
#import <opencv2/imgcodecs/ios.h>
|
||||
|
||||
@implementation MatConverters
|
||||
|
||||
+(CGImageRef)convertMatToCGImageRef:(Mat*)mat {
|
||||
return MatToCGImage(mat.nativeRef);
|
||||
}
|
||||
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image {
|
||||
return [MatConverters convertCGImageRefToMat:image alphaExist:NO];
|
||||
}
|
||||
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image alphaExist:(BOOL)alphaExist {
|
||||
Mat* mat = [Mat new];
|
||||
CGImageToMat(image, mat.nativeRef, (bool)alphaExist);
|
||||
return mat;
|
||||
}
|
||||
|
||||
+(UIImage*)converMatToUIImage:(Mat*)mat {
|
||||
return MatToUIImage(mat.nativeRef);
|
||||
}
|
||||
|
||||
+(Mat*)convertUIImageToMat:(UIImage*)image {
|
||||
return [MatConverters convertUIImageToMat:image alphaExist:NO];
|
||||
}
|
||||
|
||||
+(Mat*)convertUIImageToMat:(UIImage*)image alphaExist:(BOOL)alphaExist {
|
||||
Mat* mat = [Mat new];
|
||||
UIImageToMat(image, mat.nativeRef, (bool)alphaExist);
|
||||
return mat;
|
||||
}
|
||||
|
||||
@end
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Mat+QuickLook.h
|
||||
// MatQuickLook.h
|
||||
//
|
||||
// Created by Giles Payne on 2021/07/18.
|
||||
//
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface Mat (QuickLook)
|
||||
CV_EXPORTS @interface MatQuickLook : NSObject
|
||||
|
||||
- (id)debugQuickLookObject;
|
||||
+ (id)matDebugQuickLookObject:(Mat*)mat;
|
||||
|
||||
@end
|
||||
|
||||
+32
-33
@@ -1,11 +1,10 @@
|
||||
//
|
||||
// Mat+QuickLook.mm
|
||||
// MatQuickLook.mm
|
||||
//
|
||||
// Created by Giles Payne on 2021/07/18.
|
||||
//
|
||||
|
||||
#import "Mat+QuickLook.h"
|
||||
#import "Mat+Converters.h"
|
||||
#import "MatQuickLook.h"
|
||||
#import "Rect2i.h"
|
||||
#import "Core.h"
|
||||
#import "Imgproc.h"
|
||||
@@ -39,9 +38,9 @@ static UIFont* getSystemFont() {
|
||||
|
||||
typedef UIFont* (*FontGetter)();
|
||||
|
||||
@implementation Mat (QuickLook)
|
||||
@implementation MatQuickLook
|
||||
|
||||
- (NSString*)makeLabel:(BOOL)isIntType val:(NSNumber*)num {
|
||||
+ (NSString*)makeLabel:(BOOL)isIntType val:(NSNumber*)num {
|
||||
if (isIntType) {
|
||||
return [NSString stringWithFormat:@"%d", num.intValue];
|
||||
} else {
|
||||
@@ -56,31 +55,31 @@ typedef UIFont* (*FontGetter)();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)relativeLine:(UIBezierPath*)path relX:(CGFloat)x relY:(CGFloat)y {
|
||||
+ (void)relativeLine:(UIBezierPath*)path relX:(CGFloat)x relY:(CGFloat)y {
|
||||
CGPoint curr = path.currentPoint;
|
||||
[path addLineToPoint:CGPointMake(curr.x + x, curr.y + y)];
|
||||
}
|
||||
|
||||
- (id)debugQuickLookObject {
|
||||
if ([self dims] == 2 && [self rows] <= 10 && [self cols] <= 10 && [self channels] == 1) {
|
||||
+ (id)matDebugQuickLookObject:(Mat*)mat {
|
||||
if ([mat dims] == 2 && [mat rows] <= 10 && [mat cols] <= 10 && [mat channels] == 1) {
|
||||
FontGetter fontGetters[] = { getCMU, getBodoni72, getAnySerif, getSystemFont };
|
||||
UIFont* font = nil;
|
||||
for (int fontGetterIndex = 0; font==nil && fontGetterIndex < (sizeof(fontGetters)) / (sizeof(fontGetters[0])); fontGetterIndex++) {
|
||||
font = fontGetters[fontGetterIndex]();
|
||||
}
|
||||
int elements = [self rows] * [self cols];
|
||||
int elements = [mat rows] * [mat cols];
|
||||
NSDictionary<NSAttributedStringKey,id>* textFontAttributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: UIColor.blackColor };
|
||||
NSMutableArray<NSNumber*>* rawData = [NSMutableArray new];
|
||||
for (int dataIndex = 0; dataIndex < elements; dataIndex++) {
|
||||
[rawData addObject:[NSNumber numberWithDouble:0]];
|
||||
}
|
||||
[self get:0 col: 0 data: rawData];
|
||||
BOOL isIntType = [self depth] <= CV_32S;
|
||||
[mat get:0 col: 0 data: rawData];
|
||||
BOOL isIntType = [mat depth] <= CV_32S;
|
||||
NSMutableArray<NSString*>* labels = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString*, NSValue*>* boundingRects = [NSMutableDictionary dictionaryWithCapacity:elements];
|
||||
int maxWidth = 0, maxHeight = 0;
|
||||
for (NSNumber* number in rawData) {
|
||||
NSString* label = [self makeLabel:isIntType val:number];
|
||||
NSString* label = [MatQuickLook makeLabel:isIntType val:number];
|
||||
[labels addObject:label];
|
||||
CGRect boundingRect = [label boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:textFontAttributes context:nil];
|
||||
if (boundingRect.size.width > maxWidth) {
|
||||
@@ -97,18 +96,18 @@ typedef UIFont* (*FontGetter)();
|
||||
int borderGap = 8;
|
||||
int lineThickness = 3;
|
||||
int lipWidth = 6;
|
||||
int imageWidth = 2 * (borderGap + lipWidth) + maxWidth * [self cols] + colGap * ([self cols] - 1);
|
||||
int imageHeight = 2 * (borderGap + lipWidth) + maxHeight * [self rows] + rowGap * ([self rows] - 1);
|
||||
int imageWidth = 2 * (borderGap + lipWidth) + maxWidth * [mat cols] + colGap * ([mat cols] - 1);
|
||||
int imageHeight = 2 * (borderGap + lipWidth) + maxHeight * [mat rows] + rowGap * ([mat rows] - 1);
|
||||
|
||||
UIBezierPath* leftBracket = [UIBezierPath new];
|
||||
[leftBracket moveToPoint:CGPointMake(borderGap, borderGap)];
|
||||
[self relativeLine:leftBracket relX:0 relY:imageHeight - 2 * borderGap];
|
||||
[self relativeLine:leftBracket relX:lineThickness + lipWidth relY:0];
|
||||
[self relativeLine:leftBracket relX:0 relY:-lineThickness];
|
||||
[self relativeLine:leftBracket relX:-lipWidth relY:0];
|
||||
[self relativeLine:leftBracket relX:0 relY:-(imageHeight - 2 * (borderGap + lineThickness))];
|
||||
[self relativeLine:leftBracket relX:lipWidth relY:0];
|
||||
[self relativeLine:leftBracket relX:0 relY:-lineThickness];
|
||||
[MatQuickLook relativeLine:leftBracket relX:0 relY:imageHeight - 2 * borderGap];
|
||||
[MatQuickLook relativeLine:leftBracket relX:lineThickness + lipWidth relY:0];
|
||||
[MatQuickLook relativeLine:leftBracket relX:0 relY:-lineThickness];
|
||||
[MatQuickLook relativeLine:leftBracket relX:-lipWidth relY:0];
|
||||
[MatQuickLook relativeLine:leftBracket relX:0 relY:-(imageHeight - 2 * (borderGap + lineThickness))];
|
||||
[MatQuickLook relativeLine:leftBracket relX:lipWidth relY:0];
|
||||
[MatQuickLook relativeLine:leftBracket relX:0 relY:-lineThickness];
|
||||
[leftBracket closePath];
|
||||
CGAffineTransform reflect = CGAffineTransformConcat(CGAffineTransformMakeTranslation(-imageWidth, 0), CGAffineTransformMakeScale(-1, 1));
|
||||
UIBezierPath* rightBracket = [leftBracket copy];
|
||||
@@ -124,8 +123,8 @@ typedef UIFont* (*FontGetter)();
|
||||
[labels enumerateObjectsUsingBlock:^(id label, NSUInteger index, BOOL *stop)
|
||||
{
|
||||
CGRect boundingRect = boundingRects[label].CGRectValue;
|
||||
int row = (int)index / [self cols];
|
||||
int col = (int)index % [self cols];
|
||||
int row = (int)index / [mat cols];
|
||||
int col = (int)index % [mat cols];
|
||||
int x = borderGap + lipWidth + col * (maxWidth + colGap) + (maxWidth - boundingRect.size.width) / 2;
|
||||
int y = borderGap + lipWidth + row * (maxHeight + rowGap) + (maxHeight - boundingRect.size.height) / 2;
|
||||
CGRect textRect = CGRectMake(x, y, boundingRect.size.width, boundingRect.size.height);
|
||||
@@ -134,26 +133,26 @@ typedef UIFont* (*FontGetter)();
|
||||
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
} else if (([self dims] == 2) && ([self type] == CV_8U || [self type] == CV_8UC3 || [self type] == CV_8UC4)) {
|
||||
return [self toUIImage];
|
||||
} else if ([self dims] == 2 && [self channels] == 1) {
|
||||
} else if (([mat dims] == 2) && ([mat type] == CV_8U || [mat type] == CV_8UC3 || [mat type] == CV_8UC4)) {
|
||||
return [mat toUIImage];
|
||||
} else if ([mat dims] == 2 && [mat channels] == 1) {
|
||||
Mat* normalized = [Mat new];
|
||||
[Core normalize:self dst:normalized alpha:0 beta:255 norm_type:NORM_MINMAX dtype:CV_8U];
|
||||
Mat* normalizedKey = [[Mat alloc] initWithRows:[self rows] + 10 cols:[self cols] type:CV_8U];
|
||||
[Core normalize:mat dst:normalized alpha:0 beta:255 norm_type:NORM_MINMAX dtype:CV_8U];
|
||||
Mat* normalizedKey = [[Mat alloc] initWithRows:[mat rows] + 10 cols:[mat cols] type:CV_8U];
|
||||
std::vector<char> key;
|
||||
for (int index = 0; index < [self cols]; index++) {
|
||||
key.push_back((char)(index * 256 / [self cols]));
|
||||
for (int index = 0; index < [mat cols]; index++) {
|
||||
key.push_back((char)(index * 256 / [mat cols]));
|
||||
}
|
||||
for (int index = 0; index < 10; index++) {
|
||||
[normalizedKey put:@[[NSNumber numberWithInt:index], [NSNumber numberWithInt:0]] count:[self cols] byteBuffer:key.data()];
|
||||
[normalizedKey put:@[[NSNumber numberWithInt:index], [NSNumber numberWithInt:0]] count:[mat cols] byteBuffer:key.data()];
|
||||
}
|
||||
[normalized copyTo:[normalizedKey submatRoi:[[Rect2i alloc] initWithX:0 y:10 width:[self cols] height:[self rows]]]];
|
||||
[normalized copyTo:[normalizedKey submatRoi:[[Rect2i alloc] initWithX:0 y:10 width:[mat cols] height:[mat rows]]]];
|
||||
Mat* colorMap = [Mat new];
|
||||
[Imgproc applyColorMap:normalizedKey dst:colorMap colormap:COLORMAP_JET];
|
||||
[Imgproc cvtColor:colorMap dst:colorMap code:COLOR_BGR2RGB];
|
||||
return [colorMap toUIImage];
|
||||
}
|
||||
return [self description];
|
||||
return [mat description];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Mat+Converters.h
|
||||
//
|
||||
// Created by Masaya Tsuruta on 2020/10/08.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#import "opencv2/core.hpp"
|
||||
#else
|
||||
#define CV_EXPORTS
|
||||
#endif
|
||||
|
||||
#import "Mat.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface Mat (Converters)
|
||||
|
||||
-(CGImageRef)toCGImage CF_RETURNS_RETAINED;
|
||||
-(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
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// 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,32 @@
|
||||
//
|
||||
// Mat+Converters.h
|
||||
//
|
||||
// Created by Masaya Tsuruta on 2020/10/08.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#import "opencv2/core.hpp"
|
||||
#else
|
||||
#define CV_EXPORTS
|
||||
#endif
|
||||
|
||||
#import "Mat.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface MatConverters : NSObject
|
||||
|
||||
+(CGImageRef)convertMatToCGImageRef:(Mat*)mat CF_RETURNS_RETAINED;
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image;
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image alphaExist:(BOOL)alphaExist;
|
||||
+(NSImage*)converMatToNSImage:(Mat*)mat;
|
||||
+(Mat*)convertNSImageToMat:(NSImage*)image;
|
||||
+(Mat*)convertNSImageToMat:(NSImage*)image alphaExist:(BOOL)alphaExist;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// MatConverters.mm
|
||||
//
|
||||
// Created by Masaya Tsuruta on 2020/10/08.
|
||||
//
|
||||
|
||||
#import "MatConverters.h"
|
||||
#import <opencv2/imgcodecs/macosx.h>
|
||||
|
||||
@implementation MatConverters
|
||||
|
||||
+(CGImageRef)convertMatToCGImageRef:(Mat*)mat {
|
||||
return MatToCGImage(mat.nativeRef);
|
||||
}
|
||||
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image {
|
||||
return [MatConverters convertCGImageRefToMat:image alphaExist:NO];
|
||||
}
|
||||
|
||||
+(Mat*)convertCGImageRefToMat:(CGImageRef)image alphaExist:(BOOL)alphaExist {
|
||||
Mat* mat = [Mat new];
|
||||
CGImageToMat(image, mat.nativeRef, (bool)alphaExist);
|
||||
return mat;
|
||||
}
|
||||
|
||||
+(NSImage*)converMatToNSImage:(Mat*)mat {
|
||||
return MatToNSImage(mat.nativeRef);
|
||||
}
|
||||
|
||||
+(Mat*)convertNSImageToMat:(NSImage*)image {
|
||||
return [MatConverters convertNSImageToMat:image alphaExist:NO];
|
||||
}
|
||||
|
||||
+(Mat*)convertNSImageToMat:(NSImage*)image alphaExist:(BOOL)alphaExist {
|
||||
Mat* mat = [Mat new];
|
||||
NSImageToMat(image, mat.nativeRef, (bool)alphaExist);
|
||||
return mat;
|
||||
}
|
||||
|
||||
@end
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Mat+QuickLook.h
|
||||
// MatQuickLook.h
|
||||
//
|
||||
// Created by Giles Payne on 2021/07/18.
|
||||
//
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface Mat (QuickLook)
|
||||
CV_EXPORTS @interface MatQuickLook : NSObject
|
||||
|
||||
- (id)debugQuickLookObject;
|
||||
+ (id)matDebugQuickLookObject:(Mat*)mat;
|
||||
|
||||
@end
|
||||
|
||||
+25
-25
@@ -1,11 +1,11 @@
|
||||
//
|
||||
// Mat+QuickLook.mm
|
||||
// MatQuickLook.mm
|
||||
//
|
||||
// Created by Giles Payne on 2021/07/18.
|
||||
//
|
||||
|
||||
#import "Mat+QuickLook.h"
|
||||
#import "Mat+Converters.h"
|
||||
#import "MatQuickLook.h"
|
||||
#import "MatConverters.h"
|
||||
#import "Rect2i.h"
|
||||
#import "Core.h"
|
||||
#import "Imgproc.h"
|
||||
@@ -39,9 +39,9 @@ static NSFont* getSystemFont() {
|
||||
|
||||
typedef NSFont* (*FontGetter)();
|
||||
|
||||
@implementation Mat (QuickLook)
|
||||
@implementation MatQuickLook
|
||||
|
||||
- (NSString*)makeLabel:(BOOL)isIntType val:(NSNumber*)num {
|
||||
+ (NSString*)makeLabel:(BOOL)isIntType val:(NSNumber*)num {
|
||||
if (isIntType) {
|
||||
return [NSString stringWithFormat:@"%d", num.intValue];
|
||||
} else {
|
||||
@@ -56,27 +56,27 @@ typedef NSFont* (*FontGetter)();
|
||||
}
|
||||
}
|
||||
|
||||
- (id)debugQuickLookObject {
|
||||
+ (id)matDebugQuickLookObject:(Mat*)mat {
|
||||
// for smallish Mat objects display as a matrix
|
||||
if ([self dims] == 2 && [self rows] <= 10 && [self cols] <= 10 && [self channels] == 1) {
|
||||
if ([mat dims] == 2 && [mat rows] <= 10 && [mat cols] <= 10 && [mat channels] == 1) {
|
||||
FontGetter fontGetters[] = { getCMU, getBodoni72, getAnySerif, getSystemFont };
|
||||
NSFont* font = nil;
|
||||
for (int fontGetterIndex = 0; font==nil && fontGetterIndex < (sizeof(fontGetters)) / (sizeof(fontGetters[0])); fontGetterIndex++) {
|
||||
font = fontGetters[fontGetterIndex]();
|
||||
}
|
||||
int elements = [self rows] * [self cols];
|
||||
int elements = [mat rows] * [mat cols];
|
||||
NSDictionary<NSAttributedStringKey,id>* textFontAttributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: NSColor.blackColor };
|
||||
NSMutableArray<NSNumber*>* rawData = [NSMutableArray new];
|
||||
for (int dataIndex = 0; dataIndex < elements; dataIndex++) {
|
||||
[rawData addObject:[NSNumber numberWithDouble:0]];
|
||||
}
|
||||
[self get:0 col: 0 data: rawData];
|
||||
BOOL isIntType = [self depth] <= CV_32S;
|
||||
[mat get:0 col: 0 data: rawData];
|
||||
BOOL isIntType = [mat depth] <= CV_32S;
|
||||
NSMutableArray<NSString*>* labels = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString*, NSValue*>* boundingRects = [NSMutableDictionary dictionaryWithCapacity:elements];
|
||||
int maxWidth = 0, maxHeight = 0;
|
||||
for (NSNumber* number in rawData) {
|
||||
NSString* label = [self makeLabel:isIntType val:number];
|
||||
NSString* label = [MatQuickLook makeLabel:isIntType val:number];
|
||||
[labels addObject:label];
|
||||
NSRect boundingRect = [label boundingRectWithSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:textFontAttributes];
|
||||
if (boundingRect.size.width > maxWidth) {
|
||||
@@ -93,8 +93,8 @@ typedef NSFont* (*FontGetter)();
|
||||
int borderGap = 9;
|
||||
int lineThickness = 4;
|
||||
int lipWidth = 8;
|
||||
int imageWidth = 2 * (borderGap + lipWidth) + maxWidth * [self cols] + colGap * ([self cols] - 1);
|
||||
int imageHeight = 2 * (borderGap + lipWidth) + maxHeight * [self rows] + rowGap * ([self rows] - 1);
|
||||
int imageWidth = 2 * (borderGap + lipWidth) + maxWidth * [mat cols] + colGap * ([mat cols] - 1);
|
||||
int imageHeight = 2 * (borderGap + lipWidth) + maxHeight * [mat rows] + rowGap * ([mat rows] - 1);
|
||||
NSImage* image = [[NSImage alloc] initWithSize:NSMakeSize(imageWidth, imageHeight)];
|
||||
NSBezierPath* leftBracket = [NSBezierPath new];
|
||||
[leftBracket moveToPoint:NSMakePoint(borderGap, borderGap)];
|
||||
@@ -121,8 +121,8 @@ typedef NSFont* (*FontGetter)();
|
||||
[labels enumerateObjectsUsingBlock:^(id label, NSUInteger index, BOOL *stop)
|
||||
{
|
||||
NSRect boundingRect = boundingRects[label].rectValue;
|
||||
int row = [self rows] - 1 - ((int)index / [self cols]);
|
||||
int col = (int)index % [self cols];
|
||||
int row = [mat rows] - 1 - ((int)index / [mat cols]);
|
||||
int col = (int)index % [mat cols];
|
||||
int x = borderGap + lipWidth + col * (maxWidth + colGap) + (maxWidth - boundingRect.size.width) / 2;
|
||||
int y = borderGap + lipWidth + row * (maxHeight + rowGap) + (maxHeight - boundingRect.size.height) / 2;
|
||||
NSRect textRect = NSMakeRect(x, y, boundingRect.size.width, boundingRect.size.height);
|
||||
@@ -130,29 +130,29 @@ typedef NSFont* (*FontGetter)();
|
||||
}];
|
||||
[image unlockFocus];
|
||||
return image;
|
||||
} else if (([self dims] == 2) && ([self type] == CV_8U || [self type] == CV_8UC3 || [self type] == CV_8UC4)) {
|
||||
} else if (([mat dims] == 2) && ([mat type] == CV_8U || [mat type] == CV_8UC3 || [mat type] == CV_8UC4)) {
|
||||
// convert to NSImage if the Mats has 2 dimensions and a type and number of channels consistent with it being a image
|
||||
return [self toNSImage];
|
||||
} else if ([self dims] == 2 && [self channels] == 1) {
|
||||
return [mat toNSImage];
|
||||
} else if ([mat dims] == 2 && [mat channels] == 1) {
|
||||
// for other Mats with 2 dimensions and one channel - generate heat map
|
||||
Mat* normalized = [Mat new];
|
||||
[Core normalize:self dst:normalized alpha:0 beta:255 norm_type:NORM_MINMAX dtype:CV_8U];
|
||||
Mat* normalizedKey = [[Mat alloc] initWithRows:[self rows] + 10 cols:[self cols] type:CV_8U];
|
||||
[Core normalize:mat dst:normalized alpha:0 beta:255 norm_type:NORM_MINMAX dtype:CV_8U];
|
||||
Mat* normalizedKey = [[Mat alloc] initWithRows:[mat rows] + 10 cols:[mat cols] type:CV_8U];
|
||||
std::vector<char> key;
|
||||
for (int index = 0; index < [self cols]; index++) {
|
||||
key.push_back((char)(index * 256 / [self cols]));
|
||||
for (int index = 0; index < [mat cols]; index++) {
|
||||
key.push_back((char)(index * 256 / [mat cols]));
|
||||
}
|
||||
for (int index = 0; index < 10; index++) {
|
||||
[normalizedKey put:@[[NSNumber numberWithInt:index], [NSNumber numberWithInt:0]] count:[self cols] byteBuffer:key.data()];
|
||||
[normalizedKey put:@[[NSNumber numberWithInt:index], [NSNumber numberWithInt:0]] count:[mat cols] byteBuffer:key.data()];
|
||||
}
|
||||
[normalized copyTo:[normalizedKey submatRoi:[[Rect2i alloc] initWithX:0 y:10 width:[self cols] height:[self rows]]]];
|
||||
[normalized copyTo:[normalizedKey submatRoi:[[Rect2i alloc] initWithX:0 y:10 width:[mat cols] height:[mat rows]]]];
|
||||
Mat* colorMap = [Mat new];
|
||||
[Imgproc applyColorMap:normalizedKey dst:colorMap colormap:COLORMAP_JET];
|
||||
[Imgproc cvtColor:colorMap dst:colorMap code:COLOR_BGR2RGB];
|
||||
return [colorMap toNSImage];
|
||||
}
|
||||
//everything just return the Mat description
|
||||
return [self description];
|
||||
return [mat description];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -127,6 +127,7 @@ bool BmpDecoder::readHeader()
|
||||
++bit_count;
|
||||
}
|
||||
m_rgba_bit_offset[index_rgba] = bit_count;
|
||||
m_rgba_scale_factor[index_rgba] = 255.0f / mask;
|
||||
}
|
||||
}
|
||||
m_strm.skip( size - 56 );
|
||||
@@ -503,21 +504,33 @@ decode_rle8_bad: ;
|
||||
break;
|
||||
/************************* 32 BPP ************************/
|
||||
case 32:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
|
||||
if( !color )
|
||||
icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, Size(m_width,1) );
|
||||
else if( img.channels() == 3 )
|
||||
icvCvt_BGRA2BGR_8u_C4C3R(src, 0, data, 0, Size(m_width, 1));
|
||||
else if ( img.channels() == 4 )
|
||||
bool has_bit_mask = (m_rgba_bit_offset[0] >= 0) && (m_rgba_bit_offset[1] >= 0) && (m_rgba_bit_offset[2] >= 0);
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
bool has_bit_mask = (m_rgba_bit_offset[0] >= 0) && (m_rgba_bit_offset[1] >= 0) && (m_rgba_bit_offset[2] >= 0);
|
||||
if ( has_bit_mask )
|
||||
maskBGRA(data, src, m_width);
|
||||
else
|
||||
memcpy(data, src, m_width * 4);
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
|
||||
if( !color )
|
||||
{
|
||||
if ( has_bit_mask )
|
||||
maskBGRAtoGray(data, src, m_width);
|
||||
else
|
||||
icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
else if( img.channels() == 3 )
|
||||
{
|
||||
if ( has_bit_mask )
|
||||
maskBGRA(data, src, m_width, false);
|
||||
else
|
||||
icvCvt_BGRA2BGR_8u_C4C3R(src, 0, data, 0, Size(m_width, 1));
|
||||
}
|
||||
else if ( img.channels() == 4 )
|
||||
{
|
||||
if ( has_bit_mask )
|
||||
maskBGRA(data, src, m_width, true);
|
||||
else
|
||||
memcpy(data, src, m_width * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
@@ -538,20 +551,40 @@ void BmpDecoder::initMask()
|
||||
{
|
||||
memset(m_rgba_mask, 0, sizeof(m_rgba_mask));
|
||||
memset(m_rgba_bit_offset, -1, sizeof(m_rgba_bit_offset));
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
m_rgba_scale_factor[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void BmpDecoder::maskBGRA(uchar* des, uchar* src, int num)
|
||||
void BmpDecoder::maskBGRA(uchar* des, const uchar* src, int num, bool alpha_required)
|
||||
{
|
||||
for( int i = 0; i < num; i++, des += 4, src += 4 )
|
||||
int dest_stride = alpha_required ? 4 : 3;
|
||||
for( int i = 0; i < num; i++, des += dest_stride, src += 4 )
|
||||
{
|
||||
uint data = *((uint*)src);
|
||||
des[0] = (uchar)((m_rgba_mask[2] & data) >> m_rgba_bit_offset[2]);
|
||||
des[1] = (uchar)((m_rgba_mask[1] & data) >> m_rgba_bit_offset[1]);
|
||||
des[2] = (uchar)((m_rgba_mask[0] & data) >> m_rgba_bit_offset[0]);
|
||||
if (m_rgba_bit_offset[3] >= 0)
|
||||
des[3] = (uchar)((m_rgba_mask[3] & data) >> m_rgba_bit_offset[3]);
|
||||
else
|
||||
des[3] = 255;
|
||||
des[0] = (uchar)(((m_rgba_mask[2] & data) >> m_rgba_bit_offset[2]) * m_rgba_scale_factor[2]);
|
||||
des[1] = (uchar)(((m_rgba_mask[1] & data) >> m_rgba_bit_offset[1]) * m_rgba_scale_factor[1]);
|
||||
des[2] = (uchar)(((m_rgba_mask[0] & data) >> m_rgba_bit_offset[0]) * m_rgba_scale_factor[0]);
|
||||
if (alpha_required)
|
||||
{
|
||||
if (m_rgba_bit_offset[3] >= 0)
|
||||
des[3] = (uchar)(((m_rgba_mask[3] & data) >> m_rgba_bit_offset[3]) * m_rgba_scale_factor[3]);
|
||||
else
|
||||
des[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BmpDecoder::maskBGRAtoGray(uchar* des, const uchar* src, int num)
|
||||
{
|
||||
for( int i = 0; i < num; i++, des++, src += 4 )
|
||||
{
|
||||
uint data = *((uint*)src);
|
||||
int red = (uchar)(((m_rgba_mask[0] & data) >> m_rgba_bit_offset[0]) * m_rgba_scale_factor[0]);
|
||||
int green = (uchar)(((m_rgba_mask[1] & data) >> m_rgba_bit_offset[1]) * m_rgba_scale_factor[1]);
|
||||
int blue = (uchar)(((m_rgba_mask[2] & data) >> m_rgba_bit_offset[2]) * m_rgba_scale_factor[2]);
|
||||
|
||||
*des = (uchar)(0.299f * red + 0.587f * green + 0.114f * blue);
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -74,7 +74,8 @@ public:
|
||||
protected:
|
||||
|
||||
void initMask();
|
||||
void maskBGRA(uchar* des, uchar* src, int num);
|
||||
void maskBGRA(uchar* des, const uchar* src, int num, bool alpha_required);
|
||||
void maskBGRAtoGray(uchar* des, const uchar* src, int num);
|
||||
|
||||
enum Origin
|
||||
{
|
||||
@@ -90,6 +91,7 @@ protected:
|
||||
BmpCompression m_rle_code;
|
||||
uint m_rgba_mask[4];
|
||||
int m_rgba_bit_offset[4];
|
||||
float m_rgba_scale_factor[4];
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -695,14 +695,14 @@ bool PAMEncoder::write( const Mat& img, const std::vector<int>& params )
|
||||
|
||||
/* write header */
|
||||
tmp = 0;
|
||||
tmp += sprintf( buffer, "P7\n");
|
||||
tmp += sprintf( buffer + tmp, "WIDTH %d\n", width);
|
||||
tmp += sprintf( buffer + tmp, "HEIGHT %d\n", height);
|
||||
tmp += sprintf( buffer + tmp, "DEPTH %d\n", img.channels());
|
||||
tmp += sprintf( buffer + tmp, "MAXVAL %d\n", (1 << img.elemSize1()*8) - 1);
|
||||
tmp += snprintf( buffer, bufsize, "P7\n");
|
||||
tmp += snprintf( buffer + tmp, bufsize - tmp, "WIDTH %d\n", width);
|
||||
tmp += snprintf( buffer + tmp, bufsize - tmp, "HEIGHT %d\n", height);
|
||||
tmp += snprintf( buffer + tmp, bufsize - tmp, "DEPTH %d\n", img.channels());
|
||||
tmp += snprintf( buffer + tmp, bufsize - tmp, "MAXVAL %d\n", (1 << img.elemSize1()*8) - 1);
|
||||
if (fmt)
|
||||
tmp += sprintf( buffer + tmp, "TUPLTYPE %s\n", fmt->name );
|
||||
sprintf( buffer + tmp, "ENDHDR\n" );
|
||||
tmp += snprintf( buffer + tmp, bufsize - tmp, "TUPLTYPE %s\n", fmt->name );
|
||||
snprintf( buffer + tmp, bufsize - tmp, "ENDHDR\n" );
|
||||
|
||||
strm.putBytes( buffer, (int)strlen(buffer) );
|
||||
/* write data */
|
||||
|
||||
@@ -467,12 +467,12 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
const int code = ((mode == PXM_TYPE_PBM) ? 1 : (mode == PXM_TYPE_PGM) ? 2 : 3)
|
||||
+ (isBinary ? 3 : 0);
|
||||
|
||||
int header_sz = sprintf(buffer, "P%c\n%d %d\n",
|
||||
int header_sz = snprintf(buffer, bufferSize, "P%c\n%d %d\n",
|
||||
(char)('0' + code), width, height);
|
||||
CV_Assert(header_sz > 0);
|
||||
if (mode != PXM_TYPE_PBM)
|
||||
{
|
||||
int sz = sprintf(&buffer[header_sz], "%d\n", (1 << depth) - 1);
|
||||
int sz = snprintf(&buffer[header_sz], bufferSize - header_sz, "%d\n", (1 << depth) - 1);
|
||||
CV_Assert(sz > 0);
|
||||
header_sz += sz;
|
||||
}
|
||||
@@ -560,11 +560,11 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
for( x = 0; x < width*channels; x += channels )
|
||||
{
|
||||
sprintf( ptr, "% 4d", data[x + 2] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 4d", data[x + 2] );
|
||||
ptr += 4;
|
||||
sprintf( ptr, "% 4d", data[x + 1] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 4d", data[x + 1] );
|
||||
ptr += 4;
|
||||
sprintf( ptr, "% 4d", data[x] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 4d", data[x] );
|
||||
ptr += 4;
|
||||
*ptr++ = ' ';
|
||||
*ptr++ = ' ';
|
||||
@@ -574,11 +574,11 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
for( x = 0; x < width*channels; x += channels )
|
||||
{
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x + 2] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 6d", ((const ushort *)data)[x + 2] );
|
||||
ptr += 6;
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x + 1] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 6d", ((const ushort *)data)[x + 1] );
|
||||
ptr += 6;
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 6d", ((const ushort *)data)[x] );
|
||||
ptr += 6;
|
||||
*ptr++ = ' ';
|
||||
*ptr++ = ' ';
|
||||
@@ -591,7 +591,7 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
for( x = 0; x < width; x++ )
|
||||
{
|
||||
sprintf( ptr, "% 4d", data[x] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 4d", data[x] );
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
@@ -599,7 +599,7 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
for( x = 0; x < width; x++ )
|
||||
{
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x] );
|
||||
snprintf( ptr, bufferSize - (ptr - buffer), "% 6d", ((const ushort *)data)[x] );
|
||||
ptr += 6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ using namespace tiff_dummy_namespace;
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// to extend cvtColor() to support CV_8S, CV_16S, CV_32S and CV_64F.
|
||||
static void extend_cvtColor( InputArray _src, OutputArray _dst, int code );
|
||||
|
||||
#define CV_TIFF_CHECK_CALL(call) \
|
||||
if (0 == (call)) { \
|
||||
CV_LOG_WARNING(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed " #call); \
|
||||
@@ -1039,9 +1042,9 @@ bool TiffDecoder::readData( Mat& img )
|
||||
Rect roi_tile(0, 0, tile_width, tile_height);
|
||||
Rect roi_img(x, img_y, tile_width, tile_height);
|
||||
if (!m_hdr && ncn == 3)
|
||||
cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGB2BGR);
|
||||
extend_cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGB2BGR);
|
||||
else if (!m_hdr && ncn == 4)
|
||||
cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGBA2BGRA);
|
||||
extend_cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGBA2BGRA);
|
||||
else
|
||||
m_tile(roi_tile).copyTo(img(roi_img));
|
||||
break;
|
||||
@@ -1279,13 +1282,17 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_32F:
|
||||
sample_format = SAMPLEFORMAT_IEEEFP;
|
||||
/* FALLTHRU */
|
||||
case CV_32S:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
sample_format = SAMPLEFORMAT_INT;
|
||||
break;
|
||||
}
|
||||
case CV_32F:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
page_compression = COMPRESSION_NONE;
|
||||
sample_format = SAMPLEFORMAT_IEEEFP;
|
||||
break;
|
||||
}
|
||||
case CV_64F:
|
||||
@@ -1356,13 +1363,13 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
|
||||
case 3:
|
||||
{
|
||||
cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGR2RGB);
|
||||
extend_cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGR2RGB);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGRA2RGBA);
|
||||
extend_cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGRA2RGBA);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1424,6 +1431,57 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
|
||||
return writeLibTiff(img_vec, params);
|
||||
}
|
||||
|
||||
static void extend_cvtColor( InputArray _src, OutputArray _dst, int code )
|
||||
{
|
||||
CV_Assert( !_src.empty() );
|
||||
CV_Assert( _src.dims() == 2 );
|
||||
|
||||
// This function extend_cvtColor reorders the src channels with only thg limited condition.
|
||||
// Otherwise, it calls cvtColor.
|
||||
|
||||
const int stype = _src.type();
|
||||
if(!
|
||||
(
|
||||
(
|
||||
( stype == CV_8SC3 ) || ( stype == CV_8SC4 ) ||
|
||||
( stype == CV_16SC3 ) || ( stype == CV_16SC4 ) ||
|
||||
( stype == CV_32SC3 ) || ( stype == CV_32SC4 ) ||
|
||||
( stype == CV_64FC3 ) || ( stype == CV_64FC4 )
|
||||
)
|
||||
&&
|
||||
(
|
||||
( code == COLOR_BGR2RGB ) || ( code == COLOR_BGRA2RGBA )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
cvtColor( _src, _dst, code );
|
||||
return;
|
||||
}
|
||||
|
||||
Mat src = _src.getMat();
|
||||
|
||||
// cv::mixChannels requires the output arrays to be pre-allocated before calling the function.
|
||||
_dst.create( _src.size(), stype );
|
||||
Mat dst = _dst.getMat();
|
||||
|
||||
// BGR to RGB or BGRA to RGBA
|
||||
// src[0] -> dst[2]
|
||||
// src[1] -> dst[1]
|
||||
// src[2] -> dst[0]
|
||||
// src[3] -> dst[3] if src has alpha channel.
|
||||
std::vector<int> fromTo;
|
||||
fromTo.push_back(0); fromTo.push_back(2);
|
||||
fromTo.push_back(1); fromTo.push_back(1);
|
||||
fromTo.push_back(2); fromTo.push_back(0);
|
||||
if ( code == COLOR_BGRA2RGBA )
|
||||
{
|
||||
fromTo.push_back(3); fromTo.push_back(3);
|
||||
}
|
||||
|
||||
cv::mixChannels( src, dst, fromTo );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -331,6 +331,37 @@ TEST(Imgcodecs_Bmp, read_32bit_xrgb)
|
||||
ASSERT_EQ(data[3], 255);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Bmp, rgba_scale)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_rgba_scale.bmp";
|
||||
|
||||
Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC4, img.type());
|
||||
|
||||
uchar* data = img.ptr();
|
||||
ASSERT_EQ(data[0], 255);
|
||||
ASSERT_EQ(data[1], 255);
|
||||
ASSERT_EQ(data[2], 255);
|
||||
ASSERT_EQ(data[3], 255);
|
||||
|
||||
img = cv::imread(filenameInput, IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC3, img.type());
|
||||
|
||||
data = img.ptr();
|
||||
ASSERT_EQ(data[0], 255);
|
||||
ASSERT_EQ(data[1], 255);
|
||||
ASSERT_EQ(data[2], 255);
|
||||
|
||||
img = cv::imread(filenameInput, IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC1, img.type());
|
||||
|
||||
data = img.ptr();
|
||||
ASSERT_EQ(data[0], 255);
|
||||
}
|
||||
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
TEST(Imgcodecs_Hdr, regression)
|
||||
|
||||
@@ -14,6 +14,38 @@ namespace opencv_test { namespace {
|
||||
#define int64 int64_hack_
|
||||
#include "tiff.h"
|
||||
|
||||
// Re-define Mat type as enum for showing on Google Test.
|
||||
enum CV_ddtCn{
|
||||
_CV_8UC1 = CV_8UC1, _CV_8UC3 = CV_8UC3, _CV_8UC4 = CV_8UC4,
|
||||
_CV_8SC1 = CV_8SC1, _CV_8SC3 = CV_8SC3, _CV_8SC4 = CV_8SC4,
|
||||
_CV_16UC1 = CV_16UC1, _CV_16UC3 = CV_16UC3, _CV_16UC4 = CV_16UC4,
|
||||
_CV_16SC1 = CV_16SC1, _CV_16SC3 = CV_16SC3, _CV_16SC4 = CV_16SC4,
|
||||
_CV_32SC1 = CV_32SC1, _CV_32SC3 = CV_32SC3, _CV_32SC4 = CV_32SC4,
|
||||
_CV_16FC1 = CV_16FC1, _CV_16FC3 = CV_16FC3, _CV_16FC4 = CV_16FC4,
|
||||
_CV_32FC1 = CV_32FC1, _CV_32FC3 = CV_32FC3, _CV_32FC4 = CV_32FC4,
|
||||
_CV_64FC1 = CV_64FC1, _CV_64FC3 = CV_64FC3, _CV_64FC4 = CV_64FC4,
|
||||
};
|
||||
|
||||
static inline
|
||||
void PrintTo(const CV_ddtCn& val, std::ostream* os)
|
||||
{
|
||||
const int val_type = static_cast<int>(val);
|
||||
|
||||
switch ( CV_MAT_DEPTH(val_type) )
|
||||
{
|
||||
case CV_8U : *os << "CV_8U" ; break;
|
||||
case CV_16U : *os << "CV_16U" ; break;
|
||||
case CV_8S : *os << "CV_8S" ; break;
|
||||
case CV_16S : *os << "CV_16S" ; break;
|
||||
case CV_32S : *os << "CV_32S" ; break;
|
||||
case CV_16F : *os << "CV_16F" ; break;
|
||||
case CV_32F : *os << "CV_32F" ; break;
|
||||
case CV_64F : *os << "CV_64F" ; break;
|
||||
default : *os << "CV_???" ; break;
|
||||
}
|
||||
*os << "C" << CV_MAT_CN(val_type);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Test disabled as it uses a lot of memory.
|
||||
// It is killed with SIGKILL by out of memory killer.
|
||||
@@ -840,6 +872,69 @@ TEST(Imgcodecs_Tiff, readWrite_predictor)
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/23416
|
||||
|
||||
typedef std::pair<CV_ddtCn,bool> Imgcodes_Tiff_TypeAndComp;
|
||||
typedef testing::TestWithParam< Imgcodes_Tiff_TypeAndComp > Imgcodecs_Tiff_Types;
|
||||
|
||||
TEST_P(Imgcodecs_Tiff_Types, readWrite_alltypes)
|
||||
{
|
||||
const int mat_types = static_cast<int>(get<0>(GetParam()));
|
||||
const bool isCompAvailable = get<1>(GetParam());
|
||||
|
||||
// Create a test image.
|
||||
const Mat src = cv::Mat::zeros( 120, 160, mat_types );
|
||||
{
|
||||
// Add noise to test compression.
|
||||
cv::Mat roi = cv::Mat(src, cv::Rect(0, 0, src.cols, src.rows/2));
|
||||
cv::randu(roi, cv::Scalar(0), cv::Scalar(256));
|
||||
}
|
||||
|
||||
// Try to encode/decode the test image with LZW compression.
|
||||
std::vector<uchar> bufLZW;
|
||||
{
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_TIFF_COMPRESSION);
|
||||
params.push_back(COMPRESSION_LZW);
|
||||
ASSERT_NO_THROW(cv::imencode(".tiff", src, bufLZW, params));
|
||||
|
||||
Mat dstLZW;
|
||||
ASSERT_NO_THROW(cv::imdecode( bufLZW, IMREAD_UNCHANGED, &dstLZW));
|
||||
ASSERT_EQ(dstLZW.type(), src.type());
|
||||
ASSERT_EQ(dstLZW.size(), src.size());
|
||||
ASSERT_LE(cvtest::norm(dstLZW, src, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
}
|
||||
|
||||
// Try to encode/decode the test image with RAW.
|
||||
std::vector<uchar> bufRAW;
|
||||
{
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_TIFF_COMPRESSION);
|
||||
params.push_back(COMPRESSION_NONE);
|
||||
ASSERT_NO_THROW(cv::imencode(".tiff", src, bufRAW, params));
|
||||
|
||||
Mat dstRAW;
|
||||
ASSERT_NO_THROW(cv::imdecode( bufRAW, IMREAD_UNCHANGED, &dstRAW));
|
||||
ASSERT_EQ(dstRAW.type(), src.type());
|
||||
ASSERT_EQ(dstRAW.size(), src.size());
|
||||
ASSERT_LE(cvtest::norm(dstRAW, src, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
}
|
||||
|
||||
// Compare LZW and RAW streams.
|
||||
EXPECT_EQ(bufLZW == bufRAW, !isCompAvailable);
|
||||
}
|
||||
|
||||
Imgcodes_Tiff_TypeAndComp all_types[] = {
|
||||
{ _CV_8UC1, true }, { _CV_8UC3, true }, { _CV_8UC4, true },
|
||||
{ _CV_8SC1, true }, { _CV_8SC3, true }, { _CV_8SC4, true },
|
||||
{ _CV_16UC1, true }, { _CV_16UC3, true }, { _CV_16UC4, true },
|
||||
{ _CV_16SC1, true }, { _CV_16SC3, true }, { _CV_16SC4, true },
|
||||
{ _CV_32SC1, true }, { _CV_32SC3, true }, { _CV_32SC4, true },
|
||||
{ _CV_32FC1, false }, { _CV_32FC3, false }, { _CV_32FC4, false }, // No compression
|
||||
{ _CV_64FC1, false }, { _CV_64FC3, false }, { _CV_64FC4, false } // No compression
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AllTypes, Imgcodecs_Tiff_Types, testing::ValuesIn(all_types));
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
|
||||
Reference in New Issue
Block a user