0

カメラを使用して画像を撮影するアプリケーションがあります。アプリケーションは動作しますが、非常に遅く、画像の処理に約 10 秒かかります。

プロセスとは、つまり、回転、サムネイルの作成、およびそれらの両方のフラッシュメモリへの保存です。

アプリケーションはCordovaに基づいていますが、私はその一部を持っていません. また、これは古いモデルの iPhone 3G で実行されていますが、このアプリを新しいモデルで試しても、それほど良い結果は得られません。

主なボトルネックは、前述の CGContextDrawImage および UIImageJPEGRepresentation 関数です。

結果をできるだけ早く表示する必要があるため、そのコードを 2 番目のスレッドに分割することはできません。

2 日間検索しましたが、該当する解決策が見つかりませんでした。

また、AppleのプライベートAPIについて知りましたが、使用できません。

タイム クリティカルなコードのコード サンプルを次に示します。これを高速化する方法についてアドバイスがあれば、ぜひお寄せください。

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
    NSLog(@"TEST imagePickerController");
    NSDate* dateFunctionStart = [NSDate date];

    NSLog(@"respond...");
    if ([picker respondsToSelector:@selector(presentingViewController)]) {
        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
    } else {
        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
    }
    NSLog(@"done");

    // get the image
    NSLog(@"get the image...");
    UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage];
    NSLog(@"done");
    NSLog(@"correct image for orientation...");
    image = [self imageCorrectedForCaptureOrientation:image]; // 3 sec
    //image = [image rotate:[image imageOrientation]]; // 1 - 6 sec
    NSLog(@"done");

    NSLog(@"make thumbnail...");
    CGSize thumbnailSize = CGSizeMake(200, 200);
    UIImage *thumbnailImage = [self imageByScalingNotCroppingForSize:image toSize:thumbnailSize];
    NSLog(@"done");

    NSLog(@"jpeg representation 1...");
    NSData* imageData = UIImageJPEGRepresentation(image, 1.0); // 4 sec
    NSLog(@"done");
    NSLog(@"jpeg representation 2...");
    NSData* thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 1.0);
    NSLog(@"done");

    NSLog(@"save image and thumbnail...");
    NSString* imageRet = [self saveData:imageData toFile:self.imageName];   
    NSString* thumbRet = [self saveData:thumbnailData toFile:self.thumbnailName];
    NSLog(@"done");

    NSLog(@"array two images...");
    //NSString *jsResult = [NSString stringWithFormat:@"{%@, %@}", imageRet, thumbRet];
    NSArray *jsResultA = [NSArray arrayWithObjects:imageRet, thumbRet, nil];
    NSLog(@"done");

    NSLog(@"plugin stuff...");
    CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsArray:jsResultA];
    NSString* jsString = [result toSuccessCallbackString:self.callBackID];
    [self.webView stringByEvaluatingJavaScriptFromString:jsString];
    NSLog(@"done");

    timeFunc(dateFunctionStart, @"total time");
    NSLog(@"TEST END imagePickerController");

}

imageCorrectedForCaptureOrientationメソッドは次のとおりです。

- (UIImage*) imageCorrectedForCaptureOrientation:(UIImage*)anImage
{
    NSLog(@"IMAGE CORRECTION IN");
    NSDate* start = nil;

    float rotation_radians = 0;
    bool perpendicular = false;

    switch ([anImage imageOrientation]) {
        case UIImageOrientationUp:
            rotation_radians = 0.0;
            break;
        case UIImageOrientationDown:
            rotation_radians = M_PI; 
            break;
        case UIImageOrientationRight:
            rotation_radians = M_PI_2;
            perpendicular = true;
            break;
        case UIImageOrientationLeft:
            rotation_radians = -M_PI_2;
            perpendicular = true;
            break;
        default:
            break;
    }

    UIGraphicsBeginImageContext(CGSizeMake(anImage.size.width, anImage.size.height));
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Rotate around the center point
    CGContextTranslateCTM(context, anImage.size.width/2, anImage.size.height/2);
    CGContextRotateCTM(context, rotation_radians);

    CGContextScaleCTM(context, 1.0, -1.0);
    float width = perpendicular ? anImage.size.height : anImage.size.width;
    float height = perpendicular ? anImage.size.width : anImage.size.height;
    CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [anImage CGImage]);

    // Move the origin back since the rotation might've change it (if its 90 degrees)
    if (perpendicular) {
        CGContextTranslateCTM(context, -anImage.size.height/2, -anImage.size.width/2);
    }

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    NSLog(@"IMAGE CORRECTION OUT");

    return newImage;
}

それ以外に画像を保存するより良い方法が見つかりませんでした NSData* imageData = UIImageJPEGRepresentation(image, 1.0); // 4 sec

通常のカメラ アプリケーションはどのように高速に動作しますか? 画像を取得し、回転させ、画像をフラッシュに保存します。その効果を生み出す方法は?

どんな助けでも大歓迎です。

編集:解決策はありません。何かが起こっていることをユーザーに通知するために、いくつかのアニメーションを再生するカスタム UIView を配置します。イメージは 1.5 MB と大きいため、これらの操作にはしばらく時間がかかります。画像を取得して処理し、ディスクに保存するこのプロセス全体を高速化する解決策があるかもしれませんが、私はそれを知りません。

完全なソリューションのように見えるので、 https://github.com/matej/MBProgressHUDを決定しました。私が客観的な初心者であるため、複雑であることが判明した場合は、UIProgressView などを配置します。

とにかく、助けてくれてありがとう。

4

2 に答える 2

2

GCD を使用し、別のスレッドで画像を処理することをお勧めします.... UIImageJpegRepresentation のすべての呼び出しは、画像をデバイスのメモリにデコードするため、多くの費用がかかります...

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{

NSLog(@"TEST imagePickerController");
NSDate* dateFunctionStart = [NSDate date];

NSLog(@"respond...");
if ([picker respondsToSelector:@selector(presentingViewController)]) {
    [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
} else {
    [[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
NSLog(@"done");

// get the image
NSLog(@"get the image...");
UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSLog(@"done");
NSLog(@"correct image for orientation...");

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^(void) {
    image = [self imageCorrectedForCaptureOrientation:image]; // 3 sec
    //image = [image rotate:[image imageOrientation]]; // 1 - 6 sec
    NSLog(@"done");

    NSLog(@"make thumbnail...");
    CGSize thumbnailSize = CGSizeMake(200, 200);
    UIImage *thumbnailImage = [self imageByScalingNotCroppingForSize:image toSize:thumbnailSize];
    NSLog(@"done");

    NSLog(@"jpeg representation 1...");
    NSData* imageData = UIImageJPEGRepresentation(image, 1.0); // 4 sec
    NSLog(@"done");
    NSLog(@"jpeg representation 2...");
    NSData* thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 1.0);
    NSLog(@"done");

    NSLog(@"save image and thumbnail...");
    NSString* imageRet = [self saveData:imageData toFile:self.imageName];
    NSString* thumbRet = [self saveData:thumbnailData toFile:self.thumbnailName];
    NSLog(@"done");

    NSLog(@"array two images...");
    //NSString *jsResult = [NSString stringWithFormat:@"{%@, %@}", imageRet, thumbRet];
    NSArray *jsResultA = [NSArray arrayWithObjects:imageRet, thumbRet, nil];
    NSLog(@"done");

    dispatch_async(dispatch_get_main_queue(),^ {
        NSLog(@"plugin stuff...");
        CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsArray:jsResultA];
        NSString* jsString = [result toSuccessCallbackString:self.callBackID];
        [self.webView stringByEvaluatingJavaScriptFromString:jsString];
        NSLog(@"done");

        timeFunc(dateFunctionStart, @"total time");
        NSLog(@"TEST END imagePickerController");

    });

});

}

もう 1 つのアイデアは、Brad Larson による GPUImage を見て作業することです。ただし、フル イメージ サイズの操作は、場所、方法、方法に関係なくコストがかかることを覚えておいてください。

最良のアイデアは、アプリですぐに使用するものだけをできるだけ早く準備し、他のタスクをバックグラウンド キューで実行してそこで完了することです...

于 2012-09-18T09:10:32.870 に答える
0

CoreGraphics をより効率的にする方法を知るためにあまり使用していませんが、確かなことは、iPhone 3G がパフォーマンスのベースとなる良いモデルではないということです。また、画像のサイズも処理時間に大きく影響します。

最後に、必要に応じて、カスタム UIView サブクラスを使用して描画を行うことができます。このアプローチを採用すると、サブクラスの CALayer を CATiledLayer に変更して、効果的にバックグラウンドで描画できます。

于 2012-09-17T16:17:25.537 に答える