Изменение размера NSMutableArray в Objective-C для перехода в модель coreML - PullRequest
1 голос
/ 09 июля 2019

Я пытаюсь загрузить 2-мерное изображение, хранящееся как NSMutableArray (полуслучайного размера), изменить размер массива до 512x512, а затем передать его в модель coreML в качестве изображения (Grayscale 512x512) для прогнозирования. Есть ли эффективный способ сделать это? Сначала преобразовать массив NsMutableArray в UIImage / NSImage / CVPixelBuffer, а затем изменить его размер? Может ли какой-либо из этих типов удовлетворять входу "Изображение (Оттенки серого 512x512)"?

Я попытался преобразовать в NSImage и изменить его размер, а затем передать полученное изображение непосредственно в модель:

NSSize newSize;
newSize.height = 512;
newSize.width = 512;

const NSImage* segImage = [Viewer1.imageView nsimage:YES];
[segImage setScalesWhenResized:YES];

int widthNSI = [segImage size].width;
int heightNSI = [segImage size].height;
NSLog(@"NSImage original width: %i", widthNSI);
NSLog(@"NSImage original height: %i", heightNSI);

NSImage *resized = [[NSImage alloc] initWithSize: newSize];
[resized lockFocus];
[segImage setSize: newSize];
[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];
[segImage drawAtPoint:NSZeroPoint fromRect:CGRectMake(0, 0, newSize.width, newSize.height) operation:NSCompositeCopy fraction:1.0];
[resized unlockFocus];

int widthRES = [resized size].width;
int heightRES = [resized size].height;
NSLog(@"NSImage adjusted width: %i", widthRES);
NSLog(@"NSImage adjusted height: %i", heightRES);


coremodel_segment *model = nil;
model = [[coremodel_segment alloc] init];

Это, кажется, выплевывает измененное изображение (я не смог визуализировать, но по крайней мере размеры в порядке на основе журнала). Когда я пытаюсь сделать прогноз, я получаю:

-[MLNeuralNetworkEngine predictionFromInput:]: unrecognized selector sent to instance 0x7faf43c9a1c0

Итак, я предполагаю, что либо: 1. формат NSImage несовместим (это должен быть CVPixelFormat?), 2. я делаю что-то не так с изменением размера или 3. я вызываю функцию предиката неправильно.

Я также пытался преобразовать NSImage в CVPixel с помощью:

CVPixelBufferRef buffer = NULL;
size_t width = [resized size].width;
size_t height = [resized size].height;
size_t bitsPerComponent = 8; // *not* CGImageGetBitsPerComponent(image);
CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGBitmapInfo bi = kCGImageAlphaNoneSkipFirst; // *not* CGImageGetBitmapInfo(image);
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
CVPixelBufferCreate(kCFAllocatorDefault, width, height, k32ARGBPixelFormat, (CFDictionaryRef)d, &buffer);
CVPixelBufferLockBaseAddress(buffer, 0);
void *rasterData = CVPixelBufferGetBaseAddress(buffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
CGContextRef ctxt = CGBitmapContextCreate(rasterData, width, height, bitsPerComponent, bytesPerRow, cs, bi);
if(ctxt == NULL){
    NSLog(@"could not create context");
    return NULL;
}
NSGraphicsContext *nsctxt = [NSGraphicsContext graphicsContextWithGraphicsPort:ctxt flipped:NO];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:nsctxt];
[resized compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeCopy];
[NSGraphicsContext restoreGraphicsState];
CVPixelBufferUnlockBaseAddress(buffer, 0);
CFRelease(ctxt);

coremodel_segmentOutput *prediction = [model predictionFromData:buffer error:nil];

но я получаю ту же ошибку.

Я понимаю, что в CVPixelBufferConversionCode я перечисляю цветовое пространство как RBG, не уверенный, вызовет ли это какие-либо проблемы .. (GenericGray вызвал различные проблемы)

CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);

Не уверен, поможет ли это, но вот заголовок модели: //

// coremodel_segment.h
//
// This file was automatically generated and should not be edited.
//

#import <Foundation/Foundation.h>
#import <CoreML/CoreML.h>
#include <stdint.h>

NS_ASSUME_NONNULL_BEGIN


/// Model Prediction Input Type
API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) __attribute__((visibility("hidden")))
@interface coremodel_segmentInput : NSObject<MLFeatureProvider>

/// data as grayscale (kCVPixelFormatType_OneComponent8) image buffer, 512 pixels wide by 512 pixels high
@property (readwrite, nonatomic) CVPixelBufferRef data;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithData:(CVPixelBufferRef)data;
@end


/// Model Prediction Output Type
API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) __attribute__((visibility("hidden")))
@interface coremodel_segmentOutput : NSObject<MLFeatureProvider>

/// image as 1 x 512 x 512 3-dimensional array of doubles
@property (readwrite, nonatomic, strong) MLMultiArray * image;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithImage:(MLMultiArray *)image;
@end


/// Class for model loading and prediction
API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) __attribute__((visibility("hidden")))
@interface coremodel_segment : NSObject
@property (readonly, nonatomic, nullable) MLModel * model;
- (nullable instancetype)init;
- (nullable instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError * _Nullable * _Nullable)error;
- (nullable instancetype)initWithConfiguration:(MLModelConfiguration *)configuration error:(NSError * _Nullable * _Nullable)error API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)) __attribute__((visibility("hidden")));
- (nullable instancetype)initWithContentsOfURL:(NSURL *)url configuration:(MLModelConfiguration *)configuration error:(NSError * _Nullable * _Nullable)error API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)) __attribute__((visibility("hidden")));

/**
    Make a prediction using the standard interface
    @param input an instance of coremodel_segmentInput to predict from
    @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
    @return the prediction as coremodel_segmentOutput
*/
- (nullable coremodel_segmentOutput *)predictionFromFeatures:(coremodel_segmentInput *)input error:(NSError * _Nullable * _Nullable)error;

/**
    Make a prediction using the standard interface
    @param input an instance of coremodel_segmentInput to predict from
    @param options prediction options
    @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
    @return the prediction as coremodel_segmentOutput
*/
- (nullable coremodel_segmentOutput *)predictionFromFeatures:(coremodel_segmentInput *)input options:(MLPredictionOptions *)options error:(NSError * _Nullable * _Nullable)error;

/**
    Make a prediction using the convenience interface
    @param data as grayscale (kCVPixelFormatType_OneComponent8) image buffer, 512 pixels wide by 512 pixels high:
    @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
    @return the prediction as coremodel_segmentOutput
*/
- (nullable coremodel_segmentOutput *)predictionFromData:(CVPixelBufferRef)data error:(NSError * _Nullable * _Nullable)error;

/**
    Batch prediction
    @param inputArray array of coremodel_segmentInput instances to obtain predictions from
    @param options prediction options
    @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
    @return the predictions as NSArray<coremodel_segmentOutput *>
*/
- (nullable NSArray<coremodel_segmentOutput *> *)predictionsFromInputs:(NSArray<coremodel_segmentInput*> *)inputArray options:(MLPredictionOptions *)options error:(NSError * _Nullable * _Nullable)error API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)) __attribute__((visibility("hidden")));
@end

NS_ASSUME_NONNULL_END

Модель была сохранена с: сегмент_модель =

coremltools.converters.keras.convert('/Users/.../Downloads/model_segment.h5', input_names='data', image_input_names='data', output_names='image');
segment_model.save('/Users/.../Downloads/coremodel_segment.mlmodel');

, где я добавил имена ввода, чтобы форма ввода была изображением вместо MultiArray. Я попытался изменить строку прогноза на «данные» вместо «ввода»: coremodel_segmentOutput *вести прогноз = [модель прогнозированияFromData: ошибка буфера: ноль]; и теперь получите это в моей консоли:

Error Domain=com.apple.CoreML Code=1 UserInfo={NSLocalizedDescription=<private>, NSUnderlyingError=0x600003982340 {Error Domain=com.apple.CoreML Code=1 UserInfo={NSLocalizedDescription=<private>}}}
Failure verifying inputs.
...