Как настроить MTLTexture и MTLBuffers для Metal Performance Shaders Найти ключевые точки - PullRequest
0 голосов
/ 11 октября 2018

Проблема

Я впервые испытываю шейдеры производительности и столкнулся с проблемой во время выполнения.MTLTexture, возвращаемое MTKTextureLoader, кажется несовместимым с кодировщиком MPSImageFindKeypoints Metal Performance Shaders.

На данный момент я обнаружил только подсказку из примера кода @ warrenm для MPS, который задает MTKTextureLoaderOptionsтак же, как я сделал.Я не нашел никаких других упоминаний в документации.

Любая помощь высоко ценится.

Ошибка

/BuildRoot/Library/Caches/com.apple.xbs/Sources/MetalImage/MetalImage-121.0.2/MPSImage/Filters/MPSKeypoint.mm:166: failed assertion `Source 0x282ce8fc0 texture type (80) is unsupported

, где 0x282ce8fc0 - это MTLTexture из загрузчика текстур,Насколько я мог видеть, нет типа MTLTexture 80, перечисление колеблется до 8 или около того (не шестнадцатеричное).

Код

CGFloat w = CGImageGetWidth(_image);
CGFloat h = CGImageGetHeight(_image);
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
id<MTLCommandQueue> commandQueue = [device newCommandQueue];

NSDictionary* textureOptions = @{ MTKTextureLoaderOptionSRGB: [[NSNumber alloc] initWithBool:NO] };
id<MTLTexture> texture = [[[MTKTextureLoader alloc] initWithDevice:device] newTextureWithCGImage:_image
                                                                                         options:textureOptions
                                                                                           error:nil];
id<MTLBuffer> keypointDataBuffer;
id<MTLBuffer> keypointCountBuffer;

MTLRegion region = MTLRegionMake2D(0, 0, w, h);

id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
MPSImageKeypointRangeInfo rangeInfo = {100,0.5};
MPSImageFindKeypoints* imageFindKeypoints = [[MPSImageFindKeypoints alloc] initWithDevice:device
                                                                                     info:&rangeInfo];
[imageFindKeypoints encodeToCommandBuffer:commandBuffer
                            sourceTexture:texture
                                  regions:&region
                          numberOfRegions:1
                      keypointCountBuffer:keypointCountBuffer
                keypointCountBufferOffset:0
                       keypointDataBuffer:keypointDataBuffer
                 keypointDataBufferOffset:0];

[commandBuffer commit];

NSLog(keypointCountBuffer);
NSLog(keypointDataBuffer);

Редактировать

Послепреобразовывая мое изображение в правильный формат пикселей, я теперь инициализирую буферы следующим образом:

id<MTLBuffer> keypointDataBuffer = [device newBufferWithLength:maxKeypoints*(sizeof(MPSImageKeypointData)) options:MTLResourceOptionCPUCacheModeDefault];
id<MTLBuffer> keypointCountBuffer = [device newBufferWithLength:sizeof(int) options:MTLResourceOptionCPUCacheModeDefault];

Больше нет ошибок.Но как я могу читать содержимое сейчас?

((MPSImageKeypointData*)[keypointDataBuffer contents])[0].keypointCoordinate возвращает (0,0) для всех индексов.Также я не знаю, как читать keypointsCountBuffer.Содержимое буфера, преобразованное в значение типа int, показывает более высокое значение, чем определенные значения maxKeypoints.Я не вижу, где документы говорят, в каком формате находится буфер подсчета.

1 Ответ

0 голосов
/ 12 октября 2018

Наконец-то код запущен и просто для полноты я решил опубликовать весь код как ответ

code

id<MTLDevice> device = MTLCreateSystemDefaultDevice();
id<MTLCommandQueue> commandQueue = [device newCommandQueue];

// init textures
NSDictionary* textureOptions = @{ MTKTextureLoaderOptionSRGB: [[NSNumber alloc] initWithBool:NO] };
id<MTLTexture> texture = [[[MTKTextureLoader alloc] initWithDevice:device] newTextureWithCGImage:_lopoImage
                                                                                         options:textureOptions
                                                                                           error:nil];
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:(MTLPixelFormatR8Unorm) width:w height:h mipmapped:NO];
descriptor.usage = (MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite);
id<MTLTexture> unormTexture = [device newTextureWithDescriptor:descriptor];

// init arrays and buffers for keypoint finder
int maxKeypoints = w*h;
id<MTLBuffer> keypointDataBuffer = [device newBufferWithLength:sizeof(MPSImageKeypointData)*maxKeypoints options:MTLResourceOptionCPUCacheModeWriteCombined];
id<MTLBuffer> keypointCountBuffer = [device newBufferWithLength:sizeof(int) options:MTLResourceOptionCPUCacheModeWriteCombined];

MTLRegion region = MTLRegionMake2D(0, 0, w, h);

// init colorspace converter
CGColorSpaceRef srcColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
CGColorSpaceRef dstColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceLinearGray);

CGColorConversionInfoRef conversionInfo = CGColorConversionInfoCreate(srcColorSpace, dstColorSpace);
MPSImageConversion *conversion = [[MPSImageConversion alloc] initWithDevice:device
                                  srcAlpha:(MPSAlphaTypeAlphaIsOne)
                                 destAlpha:(MPSAlphaTypeNonPremultiplied)
                           backgroundColor:nil
                            conversionInfo:conversionInfo];

// init keypoint finder
MPSImageKeypointRangeInfo rangeInfo = {maxKeypoints,0.75};
MPSImageFindKeypoints* imageFindKeypoints = [[MPSImageFindKeypoints alloc] initWithDevice:device
                                                                                     info:&rangeInfo];

// encode command buffer
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
[conversion encodeToCommandBuffer:commandBuffer sourceTexture:texture destinationTexture:unormTexture];
[imageFindKeypoints encodeToCommandBuffer:commandBuffer
                            sourceTexture:unormTexture
                                  regions:&region
                          numberOfRegions:1
                      keypointCountBuffer:keypointCountBuffer
                keypointCountBufferOffset:0
                       keypointDataBuffer:keypointDataBuffer
                 keypointDataBufferOffset:0];

// run command buffer
[commandBuffer commit];
[commandBuffer waitUntilCompleted];

// read keypoints
int count = ((int*)[keypointCountBuffer contents])[0];
MPSImageKeypointData* keypointDataArray = ((MPSImageKeypointData*)[keypointDataBuffer contents]);
for (int i = 0 ; i<count;i++) {
    simd_ushort2 coordinate = keypointDataArray[i].keypointCoordinate;
    NSLog(@"color:%f | at:(%u,%u)", keypointDataArray[i].keypointColorValue, coordinate[0], coordinate[1] );
}

Я думаю, должен быть более умный способвыделите буферы ключевых точек с помощью [device newBufferWithBytesNoCopy], чтобы вам не нужно было копировать содержимое обратно в выделенные массивы.Просто не удалось правильно выровнять буфер.

Также я должен упомянуть, что, как мне кажется, обычно у вас будет текстура в оттенках серого после любого вида обнаружения объектов, так что часть преобразования изображения не понадобится.

...