1
0
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:
Alexander Smorkalov
2023-06-01 09:37:38 +03:00
565 changed files with 84396 additions and 17589 deletions
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
+55 -22
View File
@@ -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);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
+3 -1
View File
@@ -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];
};
+7 -7
View File
@@ -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 */
+10 -10
View File
@@ -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;
}
}
+65 -7
View File
@@ -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
+31
View File
@@ -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)
+95
View File
@@ -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));
//==================================================================================================