Objective c 如何为金属性能着色器设置MTLTexture和MTLBuffer查找关键点 问题

Objective c 如何为金属性能着色器设置MTLTexture和MTLBuffer查找关键点 问题,objective-c,metal,metalkit,metal-performance-shaders,Objective C,Metal,Metalkit,Metal Performance Shaders,我第一次尝试性能着色器,遇到了运行时问题。MTKTextureLoader返回的MTLTexture似乎与Metal Performance着色器的MPSImageFindKeypoints编码器不兼容 到目前为止,我发现的唯一提示来自于MPS上@warrenm的示例代码,它与我一样指定了MTKTextureLoaderOptions。我没有在文档中找到任何其他提及 非常感谢您的帮助 错误 其中0x282ce8fc0是纹理加载程序中的MTLTexture。 据我所知,没有MTLTexture类型

我第一次尝试性能着色器,遇到了运行时问题。MTKTextureLoader返回的MTLTexture似乎与Metal Performance着色器的MPSImageFindKeypoints编码器不兼容

到目前为止,我发现的唯一提示来自于MPS上@warrenm的示例代码,它与我一样指定了MTKTextureLoaderOptions。我没有在文档中找到任何其他提及

非常感谢您的帮助

错误 其中0x282ce8fc0是纹理加载程序中的MTLTexture。 据我所知,没有MTLTexture类型80,枚举范围最多为8左右,而不是十六进制

密码 编辑 将图像转换为正确的像素格式后,我现在初始化缓冲区,如下所示:

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。我也不知道如何读取KeyPointsOntBuffer。转换为int值的缓冲区内容显示的值高于定义的maxKeypoints。我看不出文档在哪里说明计数缓冲区的格式。

最后代码正在运行,为了完整起见,我想我应该发布整个代码作为答案

密码 我想应该有一种更聪明的方法来使用[device newBufferWithBytesNoCopy]分配关键点缓冲区,这样您就不需要将内容复制回分配的数组中。只是没有找到正确对齐缓冲区的方法


此外,我还应该提到,我想在任何类型的特征检测之后,通常都会有灰度纹理,这样就不需要图像转换部分。

最后,代码正在运行,为了完整起见,我想我应该发布整个代码作为答案

密码 我想应该有一种更聪明的方法来使用[device newBufferWithBytesNoCopy]分配关键点缓冲区,这样您就不需要将内容复制回分配的数组中。只是没有找到正确对齐缓冲区的方法


此外,我还应该提到,我想在任何类型的特征检测之后,通常都会有灰度纹理,因此不需要图像转换部分。

在编码命令之前,您真的没有设置keypointDataBuffer或keypointCountBuffer吗?可能与此无关,但可能会在内部造成破坏,从而导致该断言是一个令人同情的错误和误导。而且,这些NSLog调用无法工作。它们需要一个格式字符串。@Kenthomass是的,目前我不知道最好的方法是假设在调用encode或提交commandBuffer时,两个缓冲区都将由MPS初始化,因为文档没有指定如何设置这些缓冲区,我也不知道缓冲区需要多大。我想我可以将keypointDataBuffer设置为rangeInfo中定义的最大关键点计数,然后重试。事实上,我预计这些日志可能会出错,但我只是没有查看如何记录mtlbuffer。我只是看到我忽略了文档中的说明,即MPSImageFindKeypoints需要一个带有MTLPixelFormatR8Unorm的纹理。因此,在修正了图像像素格式之后,我确实遇到了错误,KeKPosits DigabuffER可能不是nulin ObjuleC,而不是C++,一个方法不能修改传递的参数,除非您传递它的地址。因此,考虑到它们的传递方式,该方法不可能创建缓冲区并将变量设置为指向它们。您真的没有在编码命令之前设置keypointDataBuffer或keypointCountBuffer吗?可能与此无关,但可能会在内部造成破坏,从而导致该断言是一个令人同情的错误和误导。而且,这些NSLog调用无法工作。它们需要一个格式字符串。@Kenthomass是的,目前我不知道最好的方法是假设在调用encode或提交commandBuffer时,两个缓冲区都将由MPS初始化,因为文档没有指定如何设置这些缓冲区,我也不知道缓冲区需要多大。我想我可以将keypointDataBuffer设置为rangeInfo中定义的最大关键点计数,然后重试。事实上,我预计这些日志可能会出错,但我只是没有查看如何记录mtlbuffer。我只是看到我忽略了文档中的说明,即MPSImageFindKeypoints需要一个带有MTLPixelFormatR8Unorm的纹理。因此,在修正了图像像素格式之后,我确实遇到了错误,KeKPosits DigabuffER可能不是nulin ObjuleC,而不是C++,一个方法不能修改传递的参数,除非您传递它的地址。因此,考虑到缓冲区的传递方式,该方法不可能创建缓冲区并将变量设置为指向缓冲区。
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];
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] );
}