7

基本的に、ペイント アプリケーションに色置換機能を実装したいと考えています。以下は元の出力と予想される出力です

オリジナル: オリジナル

ユーザーが選択した壁の色と、交換のためのしきい値を変更した後

希望の出力 私は2つのアプローチを試しましたが、期待どおりに動作しませんでした

アプローチ 1:色置換のため
のキューベースの Flood Fillアルゴリズムですが、出力が非常に遅くなり、壁の影が保持されませんでした。

フラッド フィル出力

アプローチ2: 別のオプションを調べてみたところ、SOからの投稿の下 にある画像の特定の色を変更するにはどうすればよいですか?

しかし、私はロジックを理解できず、ステップ 3 からのコードの実装について確信が持てませんでした。

私の理解で、各ステップごとに以下のコードを見つけてください。

1) cvCvtColor を使用して画像を RGB から HSV に変換します (色相のみを変更したい)。

 IplImage *mainImage=[self CreateIplImageFromUIImage:[UIImage imageNamed:@"original.jpg"]];
 IplImage *hsvImage = cvCreateImage(cvGetSize(mainImage), IPL_DEPTH_8U, 3);
 IplImage *threshImage = cvCreateImage(cvGetSize(mainImage), IPL_DEPTH_8U, 3);
 cvCvtColor(mainImage,hsvImage,CV_RGB2HSV);

2) 特定の許容範囲を指定する cvThreshold で色を分離します (単色ではなく、色の範囲が必要です)。

cvThreshold(hsvImage, threshImage, 0, 100, CV_THRESH_BINARY);

3) cvBlobsLib のようなブロブ検出ライブラリを使用して、最小サイズ未満の色の領域を破棄します。これにより、シーン内の同系色のドットが削除されます。元の画像またはしきい値の画像を指定する必要がありますか?

CBlobResult blobs = CBlobResult(threshImage, NULL, 0);
blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 10);

4) cvInRangeS で色をマスクし、結果のマスクを使用して新しい色相を適用します。

この関数が色の置換にどのように役立つかがわからず、提供される引数を理解できません。

5) cvMerge 新しい色相を持つ新しい画像を、手順 1 で保存した彩度と明るさのチャンネルで構成された画像とマージします。

cvMerge が HS と V の 3 つのチャネルをマージすることは理解していますが、上記の 3 つのステップの出力を使用するにはどうすればよいでしょうか。

基本的にopencvの実装に固執し、

可能であれば、opencvの実装またはその他の解決策を試してみてください。

4

2 に答える 2

4

最後に、以下のjavacvコードを使用して、必要な出力を達成することができ、同じopencvにも移植されています。

このソリューションには2つの問題があります

  1. エッジ検出がありません。輪郭を使用して達成できると思います
  2. 置き換えられた色にはフラットな色相と色相があり、ソースピクセルの色相の違いに基づいて設定する必要がありますが、それを達成する方法がわかりません。cvAddS を使用して cvSet の代わりになる場合があります

    IplImage image = cvLoadImage("sample.png");
    CvSize cvSize = cvGetSize(image);
    
    
    IplImage hsvImage = cvCreateImage(cvSize, image.depth(),image.nChannels());
    
    IplImage hChannel = cvCreateImage(cvSize, image.depth(), 1); 
            IplImage  sChannel = cvCreateImage(cvSize, image.depth(), 1); 
            IplImage  vChannel = cvCreateImage(cvSize, image.depth(), 1);
    cvSplit(hsvImage, hChannel, sChannel, vChannel, null);
    
    
    IplImage cvInRange = cvCreateImage(cvSize, image.depth(), 1);
    CvScalar source=new CvScalar(72/2,0.07*255,66,0); //source color to replace
    CvScalar from=getScaler(source,false);
    CvScalar to=getScaler(source, true);
    
    cvInRangeS(hsvImage, from , to, cvInRange);
    
    IplImage dest = cvCreateImage(cvSize, image.depth(), image.nChannels());
    
    IplImage temp = cvCreateImage(cvSize, IPL_DEPTH_8U, 2);
    cvMerge(hChannel, sChannel, null, null, temp);
    
    cvSet(temp, new CvScalar(45,255,0,0), cvInRange);// destination hue and sat
    cvSplit(temp, hChannel, sChannel, null, null);
    cvMerge(hChannel, sChannel, vChannel, null, dest);
    cvCvtColor(dest, dest, CV_HSV2BGR);
    cvSaveImage("output.png", dest);
    

しきい値を計算する方法

    CvScalar getScaler(CvScalar seed,boolean plus){
    if(plus){
        return CV_RGB(seed.red()+(seed.red()*thresold),seed.green()+(seed.green()*thresold),seed.blue()+(seed.blue()*thresold));
    }else{
        return CV_RGB(seed.red()-(seed.red()*thresold),seed.green()-(seed.green()*thresold),seed.blue()-(seed.blue()*thresold));
    }
        }
于 2013-03-01T04:47:53.257 に答える