CIDetectorTypeQRCode не может сканировать прозрачные изображения

Я пытаюсь сканировать QR-изображения, которые пользователь выбирает с диска. Я обнаружил странную проблему, из-за которой все библиотеки, которые я пробовал, не удались (старый порт CIDetector для ZXING или ZBAR). Я знаю, что есть способы добавить белый фон (например, перерисовать изображение или использовать CIFilter), чтобы изображение сканировалось.

Как правильно сканировать QR-коды с прозрачным фоном (настроить CIContext или CIDetector). (изображение ниже не сканируется на iOS и macOS).

https://en.wikipedia.org/wiki/QR_code#/media/File:QR_code_for_mobile_English_Wikipedia.svg QR-КОД ИЗОБРАЖЕНИЕ

- (void)scanImage:(CIImage *)image
{
    NSArray <CIFeature *>*features = [[self QRdetector] featuresInImage:image];
    NSLog(@"Number of features found: %lu", [features count]);
}

- (CIDetector *)QRdetector
{
    CIContext *context = [CIContext contextWithOptions:@{kCIContextWorkingColorSpace : [NSNull null]}]; //no difference using special options or nil as a context

    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy : CIDetectorAccuracyHigh, CIDetectorAspectRatio : @(1)}];
    return detector;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSURL *URL = [[NSBundle mainBundle] URLForResource:@"transparentqrcode" withExtension:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:[URL path]];

    CIImage *ciImage = [CIImage imageWithContentsOfURL:URL];

    //CUSTOM CODE TO ADD WHITE BACKGROUND
    CIFilter *filter = [CIFilter filterWithName:@"CISourceAtopCompositing"];
    [filter setDefaults];
    CIColor *whiteColor = [[CIColor alloc] initWithColor:[UIColor whiteColor]];
    CIImage *colorImage = [CIImage imageWithColor:whiteColor];

    colorImage = [colorImage imageByCroppingToRect:ciImage.extent];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:colorImage forKey:kCIInputBackgroundImageKey];
    CIImage *newImage = [filter valueForKey:kCIOutputImageKey];


    [self scanImage:ciImage];
    return YES;
}

person Marek H    schedule 25.01.2019    source источник
comment
Если я использую ваш точный код с предоставленным вами прозрачным изображением и изменяю [self scanImage:ciImage]; на [self scanImage:newImage];, я получаю 1 найденную функцию с .messageString из http://en.m.wikipedia.org   -  person DonMag    schedule 25.01.2019
comment
В комментариях написано, что я добавил белый фон в постобработке. Результирующий newImage не имеет прозрачного фона. Мой вопрос больше похож на то, почему мне нужно использовать какую-либо постобработку. Если есть способ настроить CIDetector на работу из коробки.   -  person Marek H    schedule 25.01.2019
comment
Ах, извините... я думал, вы имели в виду, что это не удалось, даже с добавлением белого фона.   -  person DonMag    schedule 25.01.2019
comment
Интересно... быстрое тестирование, кажется, показывает, что CIDetector обрабатывает альфа-канал как black... если я отредактирую ваше изображение QRCode и изменю его на что-нибудь, кроме черного (оставив прозрачные области как есть), я получу успешные результаты.   -  person DonMag    schedule 25.01.2019
comment
Тоже интересно - или любопытно? Я пробовал несколько онлайн-сканеров QRCode (загрузить изображение для сканирования). Пара вернула правильное значение для исходного черного+прозрачного изображения, но затем ошибка, когда я загрузил свою белую+прозрачную версию. Таким образом, может показаться, что эти сайты предварительно обрабатывают, заполняя/преобразовывая альфа-канал в белый цвет.   -  person DonMag    schedule 25.01.2019
comment
Я попробовал его на некоторых коммерческих сканерах в магазине приложений, и он также не работает (читатель qr для iphone по тафону, neoreader воспринимает прозрачный как черный). Знаете ли вы, есть ли более простой способ e.i. открыть как rgb (не как rgba), не переходя на низкий уровень ужина, и читать попиксельно? У Nsimage есть свойство backgroundcolor, но я не могу заставить его работать (безуспешно пытался восстановить кэш)   -  person Marek H    schedule 25.01.2019
comment
Некоторый поиск мне не помогает... Я публикую ответ, который может быть немного лучшим вариантом.   -  person DonMag    schedule 25.01.2019


Ответы (1)


Как упоминалось в комментариях, кажется, что CIDetector рассматривает альфа-канал как черный. Замена его на белый работает --- если только сам QRCode не белый с прозрачным фоном.

Я не делал никакого профилирования, чтобы посмотреть, будет ли это быстрее, но может быть лучшим вариантом.

- (IBAction)didTap:(id)sender {

    NSURL *URL = [[NSBundle mainBundle] URLForResource:@"transparentqrcode" withExtension:@"png"];

    CIImage *ciImage = [CIImage imageWithContentsOfURL:URL];

    NSArray <CIFeature *>*features = [self getImageFeatures:ciImage];

    // if CIDetector failed to find / process a QRCode in the image,
    // (such as when the image has a transparent background),
    // invert the colors and try again
    if (features.count == 0) {
        CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"];
        [filter setValue:ciImage forKey:kCIInputImageKey];
        CIImage *newImage = [filter valueForKey:kCIOutputImageKey];
        features = [self getImageFeatures:newImage];
    }

    if (features.count > 0) {
        for (CIQRCodeFeature* qrFeature in features) {
            NSLog(@"QRFeature.messageString : %@ ", qrFeature.messageString);
        }
    } else {
        NSLog(@"Unable to decode image!");
    }

}

- (NSArray <CIFeature *>*)getImageFeatures:(CIImage *)image
{
    NSArray <CIFeature *>*features = [[self QRdetector] featuresInImage:image];
    NSLog(@"Number of features found: %lu", [features count]);
    return features;
}

- (CIDetector *)QRdetector
{
    CIContext *context = [CIContext contextWithOptions:@{kCIContextWorkingColorSpace : [NSNull null]}]; //no difference using special options or nil as a context

    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy : CIDetectorAccuracyHigh, CIDetectorAspectRatio : @(1)}];
    return detector;
}
person DonMag    schedule 25.01.2019
comment
Я заполнил отчет об ошибке. rdar://47548370 Это решение работает, но я не считаю инвертирование лучшим решением, чем добавление белого фона - person Marek H; 26.01.2019