2

CGPaths を使用して座標を描画できるように、CIDetector (顔検出) の結果を、画像を表示する UIImageView に対する座標に変換するのに苦労しています。

ここですべての質問と見つけたすべてのチュートリアルを見てきましたが、それらのほとんどは、UIImageView () に表示されるときにスケーリングされない小さな画像を使用しています。私が抱えている問題はaspectFit、UIImageView に表示されるときに使用してスケーリングされる大きな画像を使用し、正しいスケール + 変換値を決定することです。

異なるサイズ/アスペクト比の画像でテストすると一貫性のない結果が得られるので、私のルーチンに欠陥があると思います. 私はしばらくこれに苦労していたので、誰かがいくつかのヒントを持っているか、私が間違っていることをX線で見ることができれば、それは大きな助けになるでしょう.

私がやっていること:

  • 顔座標を取得する
  • 以下のルーチンを使用してframeForImage(ここ SO にあります)、UIImageView 画像のスケールと境界を取得します。
  • スケール + 平行移動の変換を作成
  • CIDetector の結果に変換を適用する

// 変換値を決定するルーチン

NSDictionary* data = [self frameForImage:self.imageView.image inImageViewAspectFit:self.imageView];

CGRect scaledImageBounds = CGRectFromString([data objectForKey:@"bounds"]);
float scale = [[data objectForKey:@"scale"] floatValue];

CGAffineTransform transform = CGAffineTransformMakeScale(scale, -scale);

transform = CGAffineTransformTranslate(transform, 
          scaledImageBounds.origin.x / scale, 
          -(scaledImageBounds.origin.y / scale + scaledImageBounds.size.height / scale));

以下を使用して変換された CIDetector の結果:

     mouthPosition = CGPointApplyAffineTransform(mouthPosition, transform);

// 悪い結果の例: スケールが正しくないようです

ここに画像の説明を入力

// 'aspectFit` を使用して UIImageView でスケーリングされた画像の境界を決定するための SO の以下のルーチン

-(NSDictionary*)frameForImage:(UIImage*)image inImageViewAspectFit:(UIImageView*)myImageView
{
    float imageRatio = image.size.width / image.size.height;
    float viewRatio = myImageView.frame.size.width / myImageView.frame.size.height;

    float scale;
    CGRect boundingRect;
    if(imageRatio < viewRatio)
    {
        scale = myImageView.frame.size.height / image.size.height;
        float width = scale * image.size.width;
        float topLeftX = (myImageView.frame.size.width - width) * 0.5;
        boundingRect = CGRectMake(topLeftX, 0, width, myImageView.frame.size.height);
    }
    else
    {
        scale = myImageView.frame.size.width / image.size.width;
        float height = scale * image.size.height;
        float topLeftY = (myImageView.frame.size.height - height) * 0.5;
        boundingRect = CGRectMake(0, topLeftY, myImageView.frame.size.width, height);
    }

    NSDictionary * data = [NSDictionary dictionaryWithObjectsAndKeys:
                           [NSNumber numberWithFloat:scale], @"scale",
                           NSStringFromCGRect(boundingRect), @"bounds",
                           nil];

    return data;
}
4

2 に答える 2

4

私はあなたが何をしようとしているのかを完全に理解していますが、あなたが望むものを達成するための別の方法を提供させてください.

  • 大きすぎる画像があります
  • あなたはimageViewのサイズを知っています
  • 画像に CGImage を要求する
  • imageView の幅を画像の幅で割った「スケール」係数を決定する
  • この値と画像の高さを乗算し、imageViewHeight から結果を減算して、imageView の「空の」高さを取得し、これを「fillHeight」と呼びましょう
  • 「fillHeight」を 2 で割って丸め、以下で使用する「オフセット」値を取得します。
  • UIGraphicsBeginImageContextWithOptions(imageView.size, NO, 0) によって提供されるコンテキストを使用して、必要な色の背景をペイントしてから、CGImage を描画します

    CGContextDrawImage (context, CGRectMake(0, offset, imageView.size.width, rintf( image.size.height*scale )), [画像CGImage]);

  • 以下を使用して、この新しい画像を取得します。

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 画像を返します。

  • 画像を設定します: imageView.image = image;

正確なスケーリング比とオフセットがわかるので、イメージに正確にマッピングできます。

于 2012-08-30T17:47:55.447 に答える
0

これは、あなたが探している単純な答えかもしれません。x 座標と y 座標が反転している場合は、自分でミラーリングできます。以下のスニペットでは、返された機能をループして、y 座標を反転する必要があり、前面カメラの場合は x 座標を反転する必要があります。

    for (CIFaceFeature *f in features) {
        float newy = -f.bounds.origin.y + self.frame.size.height - f.bounds.size.height;

        float newx = f.bounds.origin.x;
        if( isMirrored ) {
            newx = -f.bounds.origin.x + self.frame.size.width - f.bounds.size.width;
        }
        [[soups objectAtIndex:rnd] drawInRect:CGRectMake(newx, newy, f.bounds.size.width, f.bounds.size.height)];
    }
于 2016-12-15T23:17:02.500 に答える