画像処理で各ピクセルごとの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関数で重複を無くせるのでしょうが…
どなたか良い方法をご教授願えませんでしょうか?
No.5ベストアンサー
- 回答日時:
重複処理の回数が少ないなら、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;の代入の意味
について教えていただければ幸いです。
初歩的な質問をしてしまっているかもしれませんが、
どうぞよろしくお願い致します。
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の方が間違い少ないってことでしょうか。
上記疑問はやはり残るので、教えていただけると幸いです。
No.8
- 回答日時:
#7さん、こんにちは
環境依存については同意、ではイニシャライザを付けることにします。
RGB(unsigned int r, unsigned int g, unsigned int b) : v(0)
もっと環境依存を少なくするには、r,g,b 個別に大小の判断をする必要がありそうです。
No.7
- 回答日時:
環境を特定していいならともかく, そうでなければ
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.
No.6
- 回答日時:
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 ;
ご回答ありがとうございます。
・unsigned int vの比較を用いることでなぜソートができるのか?
→unionについては調べていたのですが、ようやくピンと
来ました。どうも基本的に私は鈍いみたいです(-_-;)
アドレスを共有しているから間接的にcを比較することに
なるというわけですね。そして、unsigned char(8bit)*4個で
unsigned int(32bit)相当…なるほど。
検討違いの解釈をしていなければ良いですが。
No.4
- 回答日時:
内容を考えるとstd::vector<int*>でなくてstd::list<long>で32bitのビットパターン扱いの方が管理は楽でしょう。
sort()とunique()も標準で付いてきますし、ランダムアクセスの必要もなさそうですし。ところで、RGB[3]はvectorの型がint *ならその都度確保しないと処理が狂うはずですが、そちらは考慮してますか?
No.3
- 回答日時:
へ?
今挙がっているコードでは絶対にうまく動かないだろうけど, 本質的には sort + unique でもいいのでは?
まあ, #2 でも言われるように, そんなことするより set の方が簡単だけど.
No.2
- 回答日時:
データ格納の方法は、回答番号: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;
}
とやっても中身自体は参照してくれないので、
やはりうまくいかないんでしょうね…。
No.1
- 回答日時:
どうして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);
等として戻せば良かったのかもしれませんが(汗
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
関数から配列を返すには?
-
配列の要素数に変数を入れたい...
-
c言語
-
define で 配列
-
MFCのCArrayを使った二次元配列
-
エラーが出てしまいます
-
AfxBeginThread の引数について
-
C言語 ビットフィールドについて
-
c言語 構造体
-
5人分の氏名と英語、国語、数...
-
C#で構造体の配列を持った構造...
-
配列のアドレス部
-
構造体のextern方法
-
eを小数第200位くらいまで求...
-
構造体の配列 char *' 型は 'ch...
-
C言語でエラーの直し方が分かり...
-
C言語についてです 5人のテスト...
-
fclose()でセグメンテーション違反
-
C言語の2次元配列 容量が大き...
-
VB.NETにおける構造体の初期化
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
関数から配列を返すには?
-
配列の要素数に変数を入れたい...
-
define で 配列
-
構造体のextern方法
-
C言語において、 配列要素をひ...
-
C#で構造体の配列を持った構造...
-
c言語
-
コンボボックスでデフォルト値...
-
MFC - ダイアログボックスのPic...
-
MFCのCArrayを使った二次元配列
-
Cのエラー
-
int i, int i[1];
-
fclose()でセグメンテーション違反
-
C言語 数値の連続入力について
-
C言語の2次元配列 容量が大き...
-
C言語の配列のコピーについて
-
C#でのフィボナッチ数列
-
AfxBeginThread の引数について
-
C#で配列が空かを判定するには?
-
c言語プログラミング 等差数列...
おすすめ情報