dポイントプレゼントキャンペーン実施中!

画像処理で各ピクセルごとのRGB値をそれぞれ取得し、
重複を除いた形で全て表示したいと考えています。
(仮に4ピクセルしかないとして、RGB(255,255,0),
RGB(255,255,255),RGB(255,255,255),RGB(255,0,255)
といった値が取れたときにRGB(255,255,0),
RGB(255,255,255),RGB(255,0,255)のみを表示するといった感じです。)

画像ごとにピクセル数が異なり分からないので、
各ピクセルのRGB値を格納するのに動的配列vector<int*> pixelを
用い、そこにred,green,blueそれぞれの値を格納した
配列RGB[3]を格納しようと思い以下のように書いたのですが、
vector配列に配列を格納したときに重複を削除する方法が
分からず困っています。

for(int x = 0; x->width; x++) {
for(int y = 0; y->height; y++) {
/*getRGBはそのピクセルのRGB値を取得する仮想関数*/
RGB[0] = (int)getRGB(x,y,RED);
RGB[1] = (int)getRGB(x,y,GREEN);
RGB[2] = (int)getRGB(x,y,BLUE);
}
}
pixel.push_back(RGB);

と格納しても、そこからpixel配列に格納された物の中から
RGBが全て一致するものを消去する方法が分かりません。
格納していたものが配列でなければ、pixelをsortして、
unique関数で重複を無くせるのでしょうが…

どなたか良い方法をご教授願えませんでしょうか?

A 回答 (9件)

重複処理の回数が少ないなら、vector でいいです。


union を使ってみてはどうでしょうか。


// 注:このサンプルはインデントに全角の空白文字を使用
#include <iostream>
#include <vector>
#include <algorithm>

union RGB
{
  unsigned char c[4];
  unsigned int v;

  RGB() : v(0) {}
  RGB(unsigned int r, unsigned int g, unsigned int b){
    c[0] = b;  c[1] = g;  c[2] = r;  c[3] = 0;
  }

  bool operator ==(const RGB &other) {
    if( v != other.v )  return false;
    return true;
  }

  bool operator <(const RGB &other) {
    if( v < other.v )  return true;
    return false;
  }

};

struct PrintRGB
{
  void operator ()(const RGB &rgb) const {
    std::cout << std::hex << rgb.v << std::endl;
  }
};

int main()
{
  std::vector<RGB> rgb;

  rgb.push_back(RGB(12, 255, 18));
  rgb.push_back(RGB(12, 16, 18));
  rgb.push_back(RGB(12, 255, 18));
  rgb.push_back(RGB(12, 16, 18));
  rgb.push_back(RGB(12, 255, 18));

  for_each(rgb.begin(), rgb.end(), PrintRGB());
  std::cout << std::endl;

  std::sort(rgb.begin(), rgb.end());
  for_each(rgb.begin(), rgb.end(), PrintRGB());
  std::cout << std::endl;

  rgb.erase(std::unique(rgb.begin(), rgb.end()), rgb.end());
  for_each(rgb.begin(), rgb.end(), PrintRGB());
  std::cout << std::endl;
  
  return (0);
}

この回答への補足

分かりやすくコードで表していただきありがとうございます!
実装のイメージはかなり近いです。
ただ実行してみた所、c1012やcff12といった値が表示されて
しまいました。最終的に(12, 255, 18),(12, 16, 18)と
表示したかったので、rgb.c[0]みたいな形での修正を
試みたのですが、私の理解が浅くうまくできませんでした(><;)

そこで、
・unsigned int vの比較を用いることでなぜソートができるのか
-rgb.vっていったい何者(なぜ16進数表示)?
・変数cがunsigned charで確保しているのに対し、
RGB(unsigned int r, unsigned int g, unsigned int b)関数は
 なぜunsigned intなのか。
・c[3] = 0;の代入の意味
について教えていただければ幸いです。

初歩的な質問をしてしまっているかもしれませんが、
どうぞよろしくお願い致します。

補足日時:2009/08/15 17:14
    • good
    • 0
この回答へのお礼

struct PrintRGB
{
void operator ()(const RGB rgb) const {
std::cout << (int)rgb.c[2] << "," <<
(int)rgb.c[1] << "," <<
(int)rgb.c[0] << std::endl;
}
};
とすることで一応表示自体はうまくできるようになりました^^;
unsigned charは255までなら平気なのに、もっとも
int型でキャストしないといけないあたりが謎ですが。
C++のcoutは勝手に型判断してくれるので非常に便利ですが、
printfの方が間違い少ないってことでしょうか。
上記疑問はやはり残るので、教えていただけると幸いです。

お礼日時:2009/08/15 18:07

や, それもあるけど


sizeof(unsigned int) == 1
という (変な) 環境を想定する必要はないのかな, と.
    • good
    • 0

#7さん、こんにちは



環境依存については同意、ではイニシャライザを付けることにします。
RGB(unsigned int r, unsigned int g, unsigned int b) : v(0)

もっと環境依存を少なくするには、r,g,b 個別に大小の判断をする必要がありそうです。
    • good
    • 0

環境を特定していいならともかく, そうでなければ


class RGB {
public:
RGB(unsigned int r, unsigned int g, unsigned int b)
: rgb(r | (g<<8) | (b << 16)) { }
bool operator <(const RGB &another) const { return rgb < another.rgb; }
bool operator ==(const RGB &another) const { return rgb == another.rgb; }
// Add other functions
private:
unsigned int rgb;
};
の方が安全ではないかと>#5.
    • good
    • 0

No.5 での補足に対する回答です。




Q
・unsigned int vの比較を用いることでなぜソートができるのか
-rgb.vっていったい何者(なぜ16進数表示)?
について教えていただければ幸いです。
・c[3] = 0;の代入の意味

A
これについては、union を調べてください。


Q
・変数cがunsigned charで確保しているのに対し、
RGB(unsigned int r, unsigned int g, unsigned int b)関数は
 なぜunsigned intなのか。

A
RGBの実引数に unsigned int が使われる場合もあるかと思い
仮引数をそのようにしましたが、unsigned char でよいです。


Q
int型でキャストしないといけないあたりが謎ですが。
・・・
printfの方が間違い少ないってことでしょうか。

A
キャストしないと、キャラクターセットの方を出力してしまうからでしょう。
ただし、C++では (int)rgb.c[2] のようなキャストはなるべく避けます。
static_cast<int>(rgb.c[2]) か int(rgb.c[2]) を使ってください。
printf より cout の方が安全だと思いますよ。


あと
operator に const を追加してください。
bool operator ==(const RGB &other) const ;
bool operator <(const RGB &other) const ;
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

・unsigned int vの比較を用いることでなぜソートができるのか?
→unionについては調べていたのですが、ようやくピンと
 来ました。どうも基本的に私は鈍いみたいです(-_-;)
 アドレスを共有しているから間接的にcを比較することに
 なるというわけですね。そして、unsigned char(8bit)*4個で
 unsigned int(32bit)相当…なるほど。
 検討違いの解釈をしていなければ良いですが。

お礼日時:2009/08/16 15:25

内容を考えるとstd::vector<int*>でなくてstd::list<long>で32bitのビットパターン扱いの方が管理は楽でしょう。

sort()とunique()も標準で付いてきますし、ランダムアクセスの必要もなさそうですし。
ところで、RGB[3]はvectorの型がint *ならその都度確保しないと処理が狂うはずですが、そちらは考慮してますか?
    • good
    • 0

へ?


今挙がっているコードでは絶対にうまく動かないだろうけど, 本質的には sort + unique でもいいのでは?
まあ, #2 でも言われるように, そんなことするより set の方が簡単だけど.
    • good
    • 0

データ格納の方法は、回答番号:No.1 さんのおっしゃるとおりとして、


「vector配列の重複」の答えとしては、、、
格納するときに重複しているものをチェックして
重複していれば、格納をしないようにする
(vectorだとたぶん線形にサーチするんで遅いとおもうけど)

この回答への補足

vectorって線形でサーチしてたのですか…。
どうりでやたら遅いと思いました。

実際、各ピクセルごとに
for(width分) {
for(height分) {
for(vector配列の長さ分) {
if(RGB値 != 各vector配列の値) vector配列.push_back(RGB値);
}
}
}
と書いて実行した所、一時的に「応答なし」が出るくらい
処理が遅かったため、重複しないように格納するのを諦めました。
仕方が無いので、最後に
vector<int> pixel;
vector<int> it;
std::sort(pixel.begin(),pixel.end());
vector<int>::iterator end_it =
std::unique(pixel.begin(),pixel.end());
pixel.erase(end_it,test.end());
のような方法で除去していたのですが、
配列だとアドレス自体は同じアドレスを
参照しているためかこのようにうまくいきませんでした。

ちょっと私のアドレスに関する理解が浅いのかもしれません。
宣言時にアドレス指定先が決まっていて、new等で新しく領域
確保しているつもりでも実は同じアドレスだったというオチ
でしょうか。
int *rgb;
for(pixel回) {
rgb = new int[3];
pixel.push_back(rgb);
delete []rgb;
}
とやっても中身自体は参照してくれないので、
やはりうまくいかないんでしょうね…。

補足日時:2009/08/14 23:53
    • good
    • 0

どうしてred,green,blueそれぞれの値を格納した配列RGB[3]なの?


red+green*256+blue*256*256の値を格納した変数RGBにすればいいんじゃないの?

この回答への補足

さっそくのご回答ありがとうございます。
配列を選んだのは後で参照するため
そのまま格納する方法の方がコード的により
シンプルになるのでは?と考えたのと
int型の最大値を超えるので表示がマイナスに
なってしまうことがあるためです。

もっとも配列の重複に悩むくらいなら、
f272さんのおっしゃる通り
long型でtempを宣言し、
temp = red+green*256+blue*256*256;
といった形で値を格納させて、後で
blue = temp / (256*256);
green = temp / 256;
red = temp - (blue + green);
等として戻せば良かったのかもしれませんが(汗

補足日時:2009/08/14 23:09
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!