(「質問への追記・修正」側にて,そもそも密な絵を作れるのではないか?という疑問を投げかけておりますが,それはそれとして)
提示されたようなスカスカなデータを相手にするとしたら,原始的な話をすれば,下図のようにエッジ検出に使うカーネルを適当なでかさにして,各マスの値を求む際には,そのマスの中にある「有効な」画素値の平均等を用いればよいでしょう(つまり黒の画素は無視して色がある画素だけを扱う).
↑の図に描いたカーネルはかなり極端なでかさですが,まぁ相応のサイズにすればよいかと.
で,ほんとにでかいカーネルで計算するのは処理時間とかが嫌な感じでしょうから
【カーネルをでかくする ≒ 画像を縮小する】という方向で何かしら考えてやれば良いのではないかと.
(例えば,縮小結果の画素値を決める際に,元の画像の黒画素を無視するような)
とりあえず原始的なのを何の工夫も無くやってみた.
色を見るのは面倒なので,画像はグレースケールで扱った.
画像は左から
- グレースケールの原画
- でかいSobel (X方向) の結果をてきとーに可視化したもの
- 同 y方向
- {x方向, y方向}の2つから得たエッジ強度をてきとーに可視化したもの
カーネルがでかい分だけ,結果も太いが.
C++
1//作業関数.正方形領域内の,輝度値0でない画素群の輝度平均値を算出.
2double AreaAve( const cv::Mat &Src8U, int left, int top, int S )
3{
4 unsigned int Sum=0, n=0;
5 for( int dy=0; dy<S; ++dy )
6 {
7 const unsigned char *p = Src8U.ptr<unsigned char>( top + dy, left );
8 for( int dx=0; dx<S; ++dx, ++p )
9 { if( *p ){ Sum += *p; ++n; } }
10 }
11 return ( n ? double(Sum)/n : 0 );
12}
13
14//32bit float 画像をてきとーに表示するためのヘルパ.
15void Show32F( const std::string &WndName, cv::Mat &Img )
16{
17 double Min,Max;
18 cv::minMaxLoc( Img, &Min,&Max );
19 cv::Mat ShowImg( Img.size(), CV_8U );
20 double alpha = 255 / (Max-Min);
21 double beta = -Min * alpha;
22 Img.convertTo( ShowImg, ShowImg.type(), alpha,beta );
23 cv::imshow( WndName, ShowImg );
24}
25
26//main
27int main()
28{
29 cv::Mat SrcImg = cv::imread( "Dots.png", cv::IMREAD_GRAYSCALE );
30 if( SrcImg.empty() )return 0;
31
32 const int S = 7; //1マスのサイズ
33 const int KernelR = (S * 3) / 2;
34 const int dx[8] = { -1,0,1, -1,1, -1,0,1 };
35 const int dy[8] = { -1,-1,-1, 0,0, 1,1,1 };
36 const int wx[8] = { -1,0,1, -2,2, -1,0,1 };
37 const int wy[8] = { -1,-2,-1, 0,0, 1,2,1 };
38
39 cv::Mat SX = cv::Mat::zeros( SrcImg.size(), CV_32F );
40 cv::Mat SY = cv::Mat::zeros( SrcImg.size(), CV_32F );
41 cv::Mat Mag = cv::Mat::zeros( SrcImg.size(), CV_32F );
42
43 for( int cy=KernelR; cy+KernelR<SrcImg.rows; ++cy )
44 {
45 float *pSY = SY.ptr<float>( cy );
46 float *pSX = SX.ptr<float>( cy );
47 float *pMag = Mag.ptr<float>( cy );
48 for( int cx=KernelR; cx+KernelR<SrcImg.cols; ++cx )
49 {
50 double Xdir=0, Ydir=0;
51 for( int i=0; i<8; ++i )
52 {
53 double Ave = AreaAve( SrcImg, cx + dx[i]*S - S/2, cy + dy[i]*S - S/2, S );
54 Xdir += Ave * wx[i];
55 Ydir += Ave * wy[i];
56 }
57 pSX[cx] = (float)(Xdir);
58 pSY[cx] = (float)(Ydir);
59 pMag[cx] = (float)sqrt( Xdir*Xdir + Ydir*Ydir );
60 }
61 }
62
63 cv::imshow( "Src", SrcImg );
64 Show32F( "SX", SX );
65 Show32F( "SY", SY );
66 Show32F( "Mag", Mag );
67 cv::waitKey();
68 return 0;
69}