camellia 2.5.10-i486-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +58 -0
- data/doc/README +58 -0
- data/doc/camellia.dox +205 -0
- data/doc/html/annotated.html +46 -0
- data/doc/html/camellia_8h-source.html +1350 -0
- data/doc/html/camellia_8h.html +4873 -0
- data/doc/html/doxygen.css +310 -0
- data/doc/html/doxygen.png +0 -0
- data/doc/html/files.html +27 -0
- data/doc/html/ftv2blank.png +0 -0
- data/doc/html/ftv2doc.png +0 -0
- data/doc/html/ftv2folderclosed.png +0 -0
- data/doc/html/ftv2folderopen.png +0 -0
- data/doc/html/ftv2lastnode.png +0 -0
- data/doc/html/ftv2link.png +0 -0
- data/doc/html/ftv2mlastnode.png +0 -0
- data/doc/html/ftv2mnode.png +0 -0
- data/doc/html/ftv2node.png +0 -0
- data/doc/html/ftv2plastnode.png +0 -0
- data/doc/html/ftv2pnode.png +0 -0
- data/doc/html/ftv2vertline.png +0 -0
- data/doc/html/functions.html +292 -0
- data/doc/html/functions_func.html +204 -0
- data/doc/html/functions_vars.html +177 -0
- data/doc/html/globals.html +172 -0
- data/doc/html/globals_defs.html +37 -0
- data/doc/html/globals_func.html +170 -0
- data/doc/html/hierarchy.html +46 -0
- data/doc/html/index.html +8 -0
- data/doc/html/main.html +21 -0
- data/doc/html/pages.html +23 -0
- data/doc/html/structCamArithmParams.html +61 -0
- data/doc/html/structCamBasin.html +63 -0
- data/doc/html/structCamBitmapFont.html +38 -0
- data/doc/html/structCamBlobInfo.html +91 -0
- data/doc/html/structCamBlobs.html +52 -0
- data/doc/html/structCamImage.html +791 -0
- data/doc/html/structCamLabelingResults.html +47 -0
- data/doc/html/structCamLinearFilterKernel.html +64 -0
- data/doc/html/structCamMeasuresResults.html +55 -0
- data/doc/html/structCamMorphoMathsKernel.html +82 -0
- data/doc/html/structCamPoint.html +47 -0
- data/doc/html/structCamRLEImage.html +184 -0
- data/doc/html/structCamROI.html +89 -0
- data/doc/html/structCamRun.html +57 -0
- data/doc/html/structCamSepFilterKernel.html +68 -0
- data/doc/html/structCamTable.html +47 -0
- data/doc/html/structCamTableOfBasins.html +38 -0
- data/doc/html/structCamVolbergFwdParams.html +47 -0
- data/doc/html/structCamWarpingParams.html +79 -0
- data/doc/html/tab_b.gif +0 -0
- data/doc/html/tab_l.gif +0 -0
- data/doc/html/tab_r.gif +0 -0
- data/doc/html/tabs.css +102 -0
- data/doc/html/todo.html +28 -0
- data/doc/html/tree.html +132 -0
- data/doc/rtf/refman.rtf +38378 -0
- data/ext/INSTALL +9 -0
- data/ext/Makefile +139 -0
- data/ext/camellia_ruby.i +308 -0
- data/ext/camellia_ruby_wrap.cxx +16086 -0
- data/ext/extconf.rb +4 -0
- data/ext/install.rb +11 -0
- data/ext/swig_ruby.dsp +159 -0
- data/inc/camellia.h +2624 -0
- data/inc/camellia_internals.h +192 -0
- data/lib/camellia-fox.rb +39 -0
- data/test/test_arithm.rb +13 -0
- data/test/test_color_labeling.rb +45 -0
- data/test/test_copy.rb +13 -0
- data/test/test_draw.rb +15 -0
- data/test/test_fixed_filters.rb +23 -0
- data/test/test_fox.rb +106 -0
- data/test/test_fox2.rb +108 -0
- data/test/test_histogram.rb +18 -0
- data/test/test_hough.rb +29 -0
- data/test/test_labeling.rb +30 -0
- data/test/test_mask.rb +34 -0
- data/test/test_watershed.rb +35 -0
- data/test/ts_camellia.rb +10 -0
- metadata +138 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/** \file camellia_internals.h
|
|
2
|
+
* \brief Camellia Image Processing Library header file
|
|
3
|
+
* \author Bruno STEUX (ENSMP)
|
|
4
|
+
*
|
|
5
|
+
* Camellia Image Processing Library
|
|
6
|
+
*
|
|
7
|
+
|
|
8
|
+
The Camellia Image Processing Library is an open source low-level image processing library.
|
|
9
|
+
As it uses the IplImage structure to describe images, it is a good replacement to the IPL (Intel) library
|
|
10
|
+
and a good complement to the OpenCV library. It includes a lot of functions for image processing
|
|
11
|
+
(filtering, morphological mathematics, labeling, warping, loading/saving images, etc.),
|
|
12
|
+
some of them being highly optimized; It is also cross-platform and robust. It is doxygen-documented
|
|
13
|
+
and examples of use are provided.
|
|
14
|
+
|
|
15
|
+
This software library is an outcome of the Camellia european project (IST-2001-34410).
|
|
16
|
+
It was developped by the Ecole des Mines de Paris (ENSMP), in coordination with
|
|
17
|
+
the other partners of the project.
|
|
18
|
+
|
|
19
|
+
==========================================================================
|
|
20
|
+
|
|
21
|
+
Copyright (c) 2002-2006, Ecole des Mines de Paris - Centre de Robotique
|
|
22
|
+
All rights reserved.
|
|
23
|
+
|
|
24
|
+
Redistribution and use in source and binary forms, with or without
|
|
25
|
+
modification, are permitted provided that the following conditions are met:
|
|
26
|
+
|
|
27
|
+
* Redistributions of source code must retain the above copyright
|
|
28
|
+
notice, this list of conditions and the following disclaimer.
|
|
29
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
30
|
+
notice, this list of conditions and the following disclaimer
|
|
31
|
+
in the documentation and/or other materials provided with the distribution.
|
|
32
|
+
* Neither the name of the Ecole des Mines de Paris nor the names of
|
|
33
|
+
its contributors may be used to endorse or promote products
|
|
34
|
+
derived from this software without specific prior written permission.
|
|
35
|
+
|
|
36
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
37
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
38
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
39
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
40
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
41
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
42
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
43
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
44
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
45
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
46
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
47
|
+
|
|
48
|
+
==========================================================================
|
|
49
|
+
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
#ifndef _CAMELLIA_INTERNALS_H_
|
|
53
|
+
#define _CAMELLIA_INTERNALS_H_
|
|
54
|
+
|
|
55
|
+
// Binary images management
|
|
56
|
+
#ifdef CAM_64BITS
|
|
57
|
+
#ifdef _WIN32
|
|
58
|
+
#define CAM_BIT_BLOCK unsigned __int64
|
|
59
|
+
#else
|
|
60
|
+
#define CAM_BIT_BLOCK unsigned long long int
|
|
61
|
+
#endif
|
|
62
|
+
#define CAM_BIT_BLOCK_SIZE_SHIFT 6
|
|
63
|
+
#ifndef CAM_BIG_ENDIAN
|
|
64
|
+
#ifdef _WIN32
|
|
65
|
+
#define CAM_BIT_BLOCK_SWAP(x) ( \
|
|
66
|
+
(((x)&0x00000000000000ffi64)<<56)| \
|
|
67
|
+
(((x)&0x000000000000ff00i64)<<40)| \
|
|
68
|
+
(((x)&0x0000000000ff0000i64)<<24)| \
|
|
69
|
+
(((x)&0x00000000ff000000i64)<< 8)| \
|
|
70
|
+
(((x)&0x000000ff00000000i64)>> 8)| \
|
|
71
|
+
(((x)&0x0000ff0000000000i64)>>24)| \
|
|
72
|
+
(((x)&0x00ff000000000000i64)>>40)| \
|
|
73
|
+
(((x)&0xff00000000000000i64)>>56))
|
|
74
|
+
#else
|
|
75
|
+
#define CAM_BIT_BLOCK_SWAP(x) ( \
|
|
76
|
+
(((x)&0x00000000000000ffull)<<56)| \
|
|
77
|
+
(((x)&0x000000000000ff00ull)<<40)| \
|
|
78
|
+
(((x)&0x0000000000ff0000ull)<<24)| \
|
|
79
|
+
(((x)&0x00000000ff000000ull)<< 8)| \
|
|
80
|
+
(((x)&0x000000ff00000000ull)>> 8)| \
|
|
81
|
+
(((x)&0x0000ff0000000000ull)>>24)| \
|
|
82
|
+
(((x)&0x00ff000000000000ull)>>40)| \
|
|
83
|
+
(((x)&0xff00000000000000ull)>>56))
|
|
84
|
+
#endif //_WIN32
|
|
85
|
+
#else
|
|
86
|
+
#define CAM_BIT_BLOCK_SWAP(x) (x)
|
|
87
|
+
#endif
|
|
88
|
+
#else
|
|
89
|
+
#define CAM_BIT_BLOCK unsigned int
|
|
90
|
+
#define CAM_BIT_BLOCK_SIZE_SHIFT 5
|
|
91
|
+
#ifndef CAM_BIG_ENDIAN
|
|
92
|
+
#define CAM_BIT_BLOCK_SWAP(x) ((((x)&0x000000ff)<<24)|(((x)&0x0000ff00)<<8)|(((x)&0x00ff0000)>>8)|(((x)&0xff000000)>>24))
|
|
93
|
+
#else
|
|
94
|
+
#define CAM_BIT_BLOCK_SWAP(x) (x)
|
|
95
|
+
#endif
|
|
96
|
+
#endif
|
|
97
|
+
#define CAM_BIT_BLOCK_SIZE (sizeof(CAM_BIT_BLOCK)*8)
|
|
98
|
+
|
|
99
|
+
// Internal functions
|
|
100
|
+
typedef struct {
|
|
101
|
+
unsigned char *srcptr;
|
|
102
|
+
unsigned char *dstptr;
|
|
103
|
+
CamROI srcroi; // Source ROI after clipping
|
|
104
|
+
CamROI dstroi; // Dest ROI after clipping
|
|
105
|
+
int srcchoffset; // Channel offset for the source
|
|
106
|
+
int dstchoffset; // Channel offset for the destination image
|
|
107
|
+
int nChannels; // Number of effective channels (considering ROIs)
|
|
108
|
+
int srcinc; // Pixel to pixel increment
|
|
109
|
+
int dstinc; // Pixel to pixel increment
|
|
110
|
+
int srclinc; // Line to line increment
|
|
111
|
+
int dstlinc; // Line to line increment
|
|
112
|
+
int srcpinc; // Plane to plane increment
|
|
113
|
+
int dstpinc; // Plane to plane increment
|
|
114
|
+
|
|
115
|
+
int mask_xOffset;// Offset when mask doesn't fit within image boundaries
|
|
116
|
+
int mask_yOffset;// Offset when mask doesn't fit within image boundaries
|
|
117
|
+
CamRLEImage *mask; // Mask to be applied to the operation
|
|
118
|
+
CamRLEImage auto_mask; // Automatically allocated if provided mask is not RLE
|
|
119
|
+
} CamInternalROIPolicyStruct;
|
|
120
|
+
|
|
121
|
+
#define CAM_MASK_SUPPORT 1
|
|
122
|
+
#define CAM_IGNORE_COI_MISMATCH 2
|
|
123
|
+
#define CAM_NO_ROI_INTERSECTION 4
|
|
124
|
+
|
|
125
|
+
int camInternalROIPolicy(CamImage* src, CamImage *dst, CamInternalROIPolicyStruct *res, int options);
|
|
126
|
+
void camInternalROIPolicyExit(CamInternalROIPolicyStruct *res); // Call to this function is necessary only when the caller manages image bit-masking
|
|
127
|
+
|
|
128
|
+
const char *camGetErrorStr();
|
|
129
|
+
void camSetErrorStr(const char *s);
|
|
130
|
+
|
|
131
|
+
// Check arguments
|
|
132
|
+
#ifndef CAM_OPTIMIZE
|
|
133
|
+
#define CAM_CHECK_ARGS(function, condition) \
|
|
134
|
+
if (!(condition)) {camError(#function, "Bad argument : " #condition);return 0;}
|
|
135
|
+
#else
|
|
136
|
+
#define CAM_CHECK_ARGS(function, condition)
|
|
137
|
+
#endif
|
|
138
|
+
|
|
139
|
+
#ifndef CAM_OPTIMIZE
|
|
140
|
+
#define CAM_CHECK_ARGS2(function, condition, text) \
|
|
141
|
+
if (!(condition)) {camError(#function, "Bad argument : " #text);return 0;}
|
|
142
|
+
#else
|
|
143
|
+
#define CAM_CHECK_ARGS2(function, condition, text)
|
|
144
|
+
#endif
|
|
145
|
+
|
|
146
|
+
#ifndef CAM_OPTIMIZE
|
|
147
|
+
#define CAM_CHECK(function, condition) \
|
|
148
|
+
if (!(condition)) {camError(#function, NULL);return 0;}
|
|
149
|
+
#else
|
|
150
|
+
#define CAM_CHECK(function, condition)
|
|
151
|
+
#endif
|
|
152
|
+
|
|
153
|
+
// Mask management macros
|
|
154
|
+
|
|
155
|
+
#define INIT_MASK_MANAGEMENT \
|
|
156
|
+
if (iROI.mask) { \
|
|
157
|
+
run=iROI.mask->runs+1; \
|
|
158
|
+
while (run->line!=iROI.mask_yOffset) run++; \
|
|
159
|
+
} else { \
|
|
160
|
+
run=NULL; \
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#define BEGIN_MASK_MANAGEMENT(code) \
|
|
164
|
+
startx=-iROI.mask_xOffset; \
|
|
165
|
+
do { \
|
|
166
|
+
if (!iROI.mask) { \
|
|
167
|
+
endx=width; \
|
|
168
|
+
} else { \
|
|
169
|
+
do { \
|
|
170
|
+
while ((run->value==0)&&(run->line==y+iROI.mask_yOffset)) { \
|
|
171
|
+
startx+=run->length; \
|
|
172
|
+
run++; \
|
|
173
|
+
} \
|
|
174
|
+
if (run->line!=y+iROI.mask_yOffset) break; \
|
|
175
|
+
endx=startx+run->length; \
|
|
176
|
+
} while ((endx<=0)&&(run++)); \
|
|
177
|
+
if (run->line!=y+iROI.mask_yOffset) break; \
|
|
178
|
+
if (startx<0) startx=0; \
|
|
179
|
+
if (startx>width) startx=width; \
|
|
180
|
+
if (endx>width) endx=width; \
|
|
181
|
+
code \
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#define END_MASK_MANAGEMENT \
|
|
185
|
+
if (iROI.mask) { \
|
|
186
|
+
startx=endx; \
|
|
187
|
+
run++; \
|
|
188
|
+
} \
|
|
189
|
+
} while ((run)&&(run->line==y+iROI.mask_yOffset));
|
|
190
|
+
|
|
191
|
+
#endif
|
|
192
|
+
|
data/lib/camellia-fox.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require_gem 'fxruby'
|
|
3
|
+
|
|
4
|
+
require 'camellia'
|
|
5
|
+
include Camellia
|
|
6
|
+
|
|
7
|
+
class Fox::FXImage
|
|
8
|
+
def to_camellia
|
|
9
|
+
s=FXStream.new
|
|
10
|
+
mem=" "*(width*height*4)
|
|
11
|
+
s.open(FXStreamSave, width*height*4, mem)
|
|
12
|
+
unbound_savePixels=FXImage.instance_method(:savePixels)
|
|
13
|
+
bound_savePixels=unbound_savePixels.bind(self)
|
|
14
|
+
bound_savePixels.call(s)
|
|
15
|
+
image=CamImage.new(width, height, CAM_DEPTH_8U, CAM_COLORMODEL_RGBA)
|
|
16
|
+
image.set_pixels(mem)
|
|
17
|
+
return image
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Camellia::CamImage
|
|
22
|
+
def to_fox(app, picture=nil)
|
|
23
|
+
if picture==nil
|
|
24
|
+
pict=FXImage.new(app, nil, IMAGE_OWNED|IMAGE_KEEP, width, height)
|
|
25
|
+
else
|
|
26
|
+
pict=picture
|
|
27
|
+
end if
|
|
28
|
+
image=CamImage.new(width, height, CAM_DEPTH_8U, CAM_COLORMODEL_RGBA)
|
|
29
|
+
copy(image)
|
|
30
|
+
FXStream.new { |stream|
|
|
31
|
+
stream.open(FXStreamLoad, image.imageSize, image.to_s)
|
|
32
|
+
unbound_loadPixels=FXImage.instance_method(:loadPixels)
|
|
33
|
+
bound_loadPixels=unbound_loadPixels.bind(pict)
|
|
34
|
+
bound_loadPixels.call(stream)
|
|
35
|
+
}
|
|
36
|
+
return pict
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
data/test/test_arithm.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestArithm < Test::Unit::TestCase
|
|
5
|
+
def test_arithm
|
|
6
|
+
source=CamImage.new
|
|
7
|
+
# load picture chess.pgm
|
|
8
|
+
source.load_pgm("resources/chess.pgm")
|
|
9
|
+
n=source.arithm(source,source,CAM_SUB)
|
|
10
|
+
# resulting pixel sum should be 0
|
|
11
|
+
assert_equal(n,0)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestLabeling < Test::Unit::TestCase
|
|
5
|
+
def test_labeling
|
|
6
|
+
|
|
7
|
+
# load picture alfa156.bmp
|
|
8
|
+
image=CamImage.new
|
|
9
|
+
image.load_bmp("resources/alfa156.bmp")
|
|
10
|
+
yuv=image.to_yuv
|
|
11
|
+
|
|
12
|
+
# set color clusters
|
|
13
|
+
clusters=CamTable.new
|
|
14
|
+
clusters.set([
|
|
15
|
+
# Ymin Ymax Umin Umax Vmin Vmax
|
|
16
|
+
0, 60, 0, 255, 0, 255, # Black
|
|
17
|
+
230, 255, 0, 255, 0, 255, # White
|
|
18
|
+
0, 255, 0, 255, 140, 255 # Red
|
|
19
|
+
])
|
|
20
|
+
cluster_colors=[cam_rgb(0,0,0),cam_rgb(255,255,255),cam_rgb(255,0,0)]
|
|
21
|
+
|
|
22
|
+
# threshold and encode
|
|
23
|
+
encoded=yuv.encode_color(clusters)
|
|
24
|
+
puts "Number of runs : #{encoded.nb_runs}"
|
|
25
|
+
|
|
26
|
+
# labeling
|
|
27
|
+
blobs=encoded.labeling!
|
|
28
|
+
puts "#{blobs.nb_blobs} blobs detected"
|
|
29
|
+
|
|
30
|
+
# print and deaw the results
|
|
31
|
+
i=0
|
|
32
|
+
blobs.each {|b|
|
|
33
|
+
puts "Blob #{i} : Val=#{b.value} (#{b.top},#{b.left},#{b.width},#{b.height}) Surface=#{b.surface}"
|
|
34
|
+
image.draw_rectangle(b.left,b.top,b.left+b.width-1,b.top+b.height-1,cluster_colors[b.value-1])
|
|
35
|
+
i=i+1
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# save the result
|
|
39
|
+
image.save_bmp("output/ruby_alfa156_labeling.bmp")
|
|
40
|
+
|
|
41
|
+
# assertions
|
|
42
|
+
assert_equal(encoded.nb_runs,3026)
|
|
43
|
+
assert_equal(blobs.nb_blobs,190)
|
|
44
|
+
end
|
|
45
|
+
end
|
data/test/test_copy.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestCopy < Test::Unit::TestCase
|
|
5
|
+
def test_copy
|
|
6
|
+
source=CamImage.new
|
|
7
|
+
# load picture alfa156.bmp
|
|
8
|
+
source.load_bmp("resources/alfa156.bmp")
|
|
9
|
+
dest=CamImage.new(source.width,source.height,CAM_DEPTH_8U,CAM_COLORMODEL_RGBA)
|
|
10
|
+
source.copy(dest)
|
|
11
|
+
dest.save_bmp("output/copy_alfa156.bmp")
|
|
12
|
+
end
|
|
13
|
+
end
|
data/test/test_draw.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
|
|
5
|
+
class TestDraw < Test::Unit::TestCase
|
|
6
|
+
def test_draw
|
|
7
|
+
image=CamImage.new(320,240,CAM_DEPTH_8U,CAM_COLORMODEL_RGB)
|
|
8
|
+
font=CamBitmapFont.new('resources/fonts/xenon2.bmp')
|
|
9
|
+
image.set!(0)
|
|
10
|
+
image.draw_line(0,0,320,240,cam_rgb(255,0,0))
|
|
11
|
+
image.fill_color(50,100,cam_rgb(255,0,0))
|
|
12
|
+
image.draw_text_bitmap('Hello World',100,140,font)
|
|
13
|
+
image.save_bmp('output/drawing_ruby.bmp')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestFixedFilters < Test::Unit::TestCase
|
|
5
|
+
def test_fixed_filters
|
|
6
|
+
source=CamImage.new
|
|
7
|
+
result=CamImage.new
|
|
8
|
+
# load picture chess.pgm
|
|
9
|
+
source.load_pgm("resources/chess.pgm")
|
|
10
|
+
# gaussian filtering 3x3
|
|
11
|
+
source.fixed_filter(result,CAM_GAUSSIAN_3x3);
|
|
12
|
+
# save the result
|
|
13
|
+
result.save_pgm("output/ruby_chess_gaussian_3x3.pgm");
|
|
14
|
+
# gaussian filtering 5x5
|
|
15
|
+
source.fixed_filter(result,CAM_GAUSSIAN_5x5);
|
|
16
|
+
# save the result
|
|
17
|
+
result.save_pgm("output/ruby_chess_gaussian_5x5.pgm");
|
|
18
|
+
# gaussian filtering 7x7
|
|
19
|
+
source.fixed_filter(result,CAM_GAUSSIAN_7x7);
|
|
20
|
+
# save the result
|
|
21
|
+
result.save_pgm("output/ruby_chess_gaussian_7x7.pgm");
|
|
22
|
+
end
|
|
23
|
+
end
|
data/test/test_fox.rb
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require_gem 'fxruby'
|
|
3
|
+
include Fox
|
|
4
|
+
|
|
5
|
+
require_gem 'camellia'
|
|
6
|
+
require 'camellia-fox.rb'
|
|
7
|
+
include Camellia
|
|
8
|
+
|
|
9
|
+
class ImageWindow < FXMainWindow
|
|
10
|
+
|
|
11
|
+
def initialize(app)
|
|
12
|
+
# Invoke base class initializer first
|
|
13
|
+
super(app, "Camellia/FXRuby test", nil, nil, DECOR_ALL, 0, 0, 440, 240)
|
|
14
|
+
|
|
15
|
+
contents = FXHorizontalFrame.new(self,
|
|
16
|
+
LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
17
|
+
|
|
18
|
+
# RIGHT pane for the buttons
|
|
19
|
+
buttonFrame = FXVerticalFrame.new(contents, (FRAME_SUNKEN|LAYOUT_FILL_Y|
|
|
20
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 10, 10)
|
|
21
|
+
|
|
22
|
+
# Label above the buttons
|
|
23
|
+
FXLabel.new(buttonFrame, "Button Frame", nil,
|
|
24
|
+
JUSTIFY_CENTER_X|LAYOUT_FILL_X);
|
|
25
|
+
|
|
26
|
+
# Horizontal divider line
|
|
27
|
+
FXHorizontalSeparator.new(buttonFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X)
|
|
28
|
+
|
|
29
|
+
# Erode button
|
|
30
|
+
erodeBtn = FXButton.new(buttonFrame,
|
|
31
|
+
"Erode Image...\tGrey scale erosion",
|
|
32
|
+
nil, nil, 0, (FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|
|
|
33
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 5, 5) { |button|
|
|
34
|
+
button.connect(SEL_COMMAND, method(:onCmdErode))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Save button
|
|
38
|
+
saveBtn = FXButton.new(buttonFrame,
|
|
39
|
+
"Save Image...\tRead back image and save to file",
|
|
40
|
+
nil, nil, 0, (FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|
|
|
41
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 5, 5)
|
|
42
|
+
saveBtn.connect(SEL_COMMAND, method(:onCmdRestore))
|
|
43
|
+
|
|
44
|
+
# Exit button
|
|
45
|
+
FXButton.new(buttonFrame, "E&xit\tQuit FXRuby test", nil,
|
|
46
|
+
getApp(), FXApp::ID_QUIT, (FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|
|
|
47
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 5, 5)
|
|
48
|
+
|
|
49
|
+
# Create a FXBMPImage and load a picture from disk
|
|
50
|
+
@picture=FXBMPImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_OWNED, 320, 240);
|
|
51
|
+
FXFileStream.open('resources/alfa156.bmp', FXStreamLoad) { |stream| @picture.loadPixels(stream) }
|
|
52
|
+
@picture.render
|
|
53
|
+
source=@picture.to_camellia
|
|
54
|
+
@image=source.to_yuv
|
|
55
|
+
@image.set_roi(CamROI.new(@image,1)) # Select Y plane (B&W)
|
|
56
|
+
|
|
57
|
+
@imgFrame=FXImageFrame.new(contents,@picture)
|
|
58
|
+
|
|
59
|
+
# Make a tip
|
|
60
|
+
FXToolTip.new(getApp())
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Create and initialize
|
|
64
|
+
def create
|
|
65
|
+
# Create the windows
|
|
66
|
+
super
|
|
67
|
+
|
|
68
|
+
# Make the main window appear
|
|
69
|
+
show(PLACEMENT_SCREEN)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Restore image from offscreen pixmap
|
|
73
|
+
def onCmdRestore(sender, sel, ptr)
|
|
74
|
+
saveDialog = FXFileDialog.new(self, "Save as BMP")
|
|
75
|
+
if saveDialog.execute != 0
|
|
76
|
+
@picture.restore
|
|
77
|
+
# Get back a CamImage and save it
|
|
78
|
+
@picture.to_camellia.save_bmp(saveDialog.filename)
|
|
79
|
+
end
|
|
80
|
+
return 1
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Erode image
|
|
84
|
+
def onCmdErode(sender, sel, ptr)
|
|
85
|
+
@image.erode_circle5!
|
|
86
|
+
@image.to_fox(getApp(),@picture)
|
|
87
|
+
@picture.render
|
|
88
|
+
@imgFrame.update
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if __FILE__ == $0
|
|
94
|
+
# Make application
|
|
95
|
+
application = FXApp.new("Camellia/FXRuby", "Camellia/FXRuby test")
|
|
96
|
+
|
|
97
|
+
# Make the main window
|
|
98
|
+
ImageWindow.new(application)
|
|
99
|
+
|
|
100
|
+
# Create the application window and resources
|
|
101
|
+
application.create
|
|
102
|
+
|
|
103
|
+
# Run the application
|
|
104
|
+
application.run
|
|
105
|
+
end
|
|
106
|
+
|
data/test/test_fox2.rb
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require_gem 'fxruby'
|
|
3
|
+
include Fox
|
|
4
|
+
|
|
5
|
+
require_gem 'camellia'
|
|
6
|
+
require 'camellia-fox.rb'
|
|
7
|
+
include Camellia
|
|
8
|
+
|
|
9
|
+
class ImageWindow < FXMainWindow
|
|
10
|
+
|
|
11
|
+
def initialize(app)
|
|
12
|
+
# Invoke base class initializer first
|
|
13
|
+
super(app, "Camellia/FXRuby test", nil, nil, DECOR_ALL, 0, 0, 440, 240)
|
|
14
|
+
|
|
15
|
+
contents = FXHorizontalFrame.new(self,
|
|
16
|
+
LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
17
|
+
|
|
18
|
+
# RIGHT pane for the buttons
|
|
19
|
+
buttonFrame = FXVerticalFrame.new(contents, (FRAME_SUNKEN|LAYOUT_FILL_Y|
|
|
20
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 10, 10)
|
|
21
|
+
|
|
22
|
+
# Label above the buttons
|
|
23
|
+
FXLabel.new(buttonFrame, "Button Frame", nil,
|
|
24
|
+
JUSTIFY_CENTER_X|LAYOUT_FILL_X);
|
|
25
|
+
|
|
26
|
+
# Horizontal divider line
|
|
27
|
+
FXHorizontalSeparator.new(buttonFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X)
|
|
28
|
+
|
|
29
|
+
# Erode button
|
|
30
|
+
erodeBtn = FXButton.new(buttonFrame,
|
|
31
|
+
"Erode Image...\tGrey scale erosion",
|
|
32
|
+
nil, nil, 0, (FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|
|
|
33
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 5, 5) { |button|
|
|
34
|
+
button.connect(SEL_COMMAND, method(:onCmdErode))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Save button
|
|
38
|
+
saveBtn = FXButton.new(buttonFrame,
|
|
39
|
+
"Save Image...\tRead back image and save to file",
|
|
40
|
+
nil, nil, 0, (FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|
|
|
41
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 5, 5)
|
|
42
|
+
saveBtn.connect(SEL_COMMAND, method(:onCmdRestore))
|
|
43
|
+
|
|
44
|
+
# Exit button
|
|
45
|
+
FXButton.new(buttonFrame, "E&xit\tQuit FXRuby test", nil,
|
|
46
|
+
getApp(), FXApp::ID_QUIT, (FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|
|
|
47
|
+
LAYOUT_TOP|LAYOUT_LEFT), 0, 0, 0, 0, 10, 10, 5, 5)
|
|
48
|
+
|
|
49
|
+
# Load image using Camellia
|
|
50
|
+
source=CamImage.new
|
|
51
|
+
source.load_bmp("resources/alfa156.bmp")
|
|
52
|
+
@image=source.to_yuv
|
|
53
|
+
@image.set_roi(CamROI.new(@image,1)) # Select Y plane (B&W)
|
|
54
|
+
|
|
55
|
+
# Create a FXImage from the Camellia image
|
|
56
|
+
@picture=@image.to_fox(getApp())
|
|
57
|
+
@picture.render
|
|
58
|
+
|
|
59
|
+
@imgFrame=FXImageFrame.new(contents,@picture)
|
|
60
|
+
|
|
61
|
+
# Make a tip
|
|
62
|
+
FXToolTip.new(getApp())
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Create and initialize
|
|
66
|
+
def create
|
|
67
|
+
# Create the windows
|
|
68
|
+
super
|
|
69
|
+
|
|
70
|
+
# Make the main window appear
|
|
71
|
+
show(PLACEMENT_SCREEN)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Restore image from offscreen pixmap
|
|
75
|
+
def onCmdRestore(sender, sel, ptr)
|
|
76
|
+
saveDialog = FXFileDialog.new(self, "Save as BMP")
|
|
77
|
+
if saveDialog.execute != 0
|
|
78
|
+
@picture.restore
|
|
79
|
+
# Get back a CamImage and save it
|
|
80
|
+
@picture.to_camellia.save_bmp(saveDialog.filename)
|
|
81
|
+
end
|
|
82
|
+
return 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Erode image
|
|
86
|
+
def onCmdErode(sender, sel, ptr)
|
|
87
|
+
@image.erode_circle5!
|
|
88
|
+
@image.to_fox(getApp(),@picture)
|
|
89
|
+
@picture.render
|
|
90
|
+
@imgFrame.update
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if __FILE__ == $0
|
|
96
|
+
# Make application
|
|
97
|
+
application = FXApp.new("Camellia/FXRuby", "Camellia/FXRuby test")
|
|
98
|
+
|
|
99
|
+
# Make the main window
|
|
100
|
+
ImageWindow.new(application)
|
|
101
|
+
|
|
102
|
+
# Create the application window and resources
|
|
103
|
+
application.create
|
|
104
|
+
|
|
105
|
+
# Run the application
|
|
106
|
+
application.run
|
|
107
|
+
end
|
|
108
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestHistogram < Test::Unit::TestCase
|
|
5
|
+
def test_histogram
|
|
6
|
+
source=CamImage.new
|
|
7
|
+
# load picture alfa156.bmp
|
|
8
|
+
source.load_bmp("resources/alfa156.bmp")
|
|
9
|
+
# convert to YUV
|
|
10
|
+
yuv=CamImage.new
|
|
11
|
+
yuv=source.to_yuv
|
|
12
|
+
# compute the histogram
|
|
13
|
+
result=CamImage.new
|
|
14
|
+
yuv.histogram_2_channels(2,3,result)
|
|
15
|
+
# save the result
|
|
16
|
+
result.save_pgm("output/alfa156_histo.pgm")
|
|
17
|
+
end
|
|
18
|
+
end
|
data/test/test_hough.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestHough < Test::Unit::TestCase
|
|
5
|
+
def test_hough
|
|
6
|
+
image=CamImage.new(100,100)
|
|
7
|
+
# Draw a filled circle in mask
|
|
8
|
+
image.set!(0)
|
|
9
|
+
image.draw_circle(40,40,50,128)
|
|
10
|
+
image.fill_color(40,40,128)
|
|
11
|
+
res=image.hough_circle(10,40,60)
|
|
12
|
+
puts "Found a circle at (#{res[1]},#{res[2]}) (radius=#{res[3]}) (confidence=#{res[0]})"
|
|
13
|
+
assert((res[1]-40).abs<=1)
|
|
14
|
+
assert((res[2]-40).abs<=1)
|
|
15
|
+
|
|
16
|
+
for i in 1..3 do
|
|
17
|
+
# Load an image with a road sign
|
|
18
|
+
image.load_bmp("resources/road#{i}.bmp")
|
|
19
|
+
yuv=CamImage.new
|
|
20
|
+
image.to_yuv(yuv)
|
|
21
|
+
yuv.set_roi(CamROI.new(1,8,8,image.width-16,image.height-128))
|
|
22
|
+
yuv.fixed_filter!(CAM_GAUSSIAN_3x3)
|
|
23
|
+
res=yuv.hough_circle(100,6,25)
|
|
24
|
+
image.draw_circle(res[1],res[2],res[3],cam_rgb(255,0,0))
|
|
25
|
+
image.save_bmp("output/road_circle_hough#{i}.bmp")
|
|
26
|
+
puts "Found a circle at (#{res[1]},#{res[2]}) (radius=#{res[3]}) (confidence=#{res[0]})"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestLabeling < Test::Unit::TestCase
|
|
5
|
+
def test_labeling
|
|
6
|
+
image=CamImage.new
|
|
7
|
+
# load picture alfa156.bmp
|
|
8
|
+
image.load_bmp("resources/alfa156.bmp")
|
|
9
|
+
yuv=image.to_yuv
|
|
10
|
+
# consider only the V plane (red)
|
|
11
|
+
yuv.set_roi(CamROI.new(yuv,3))
|
|
12
|
+
# threshold and encode
|
|
13
|
+
thr=yuv.encode_threshold(150)
|
|
14
|
+
# labeling
|
|
15
|
+
blobs=thr.labeling!
|
|
16
|
+
puts "#{blobs.nb_blobs} blobs detected"
|
|
17
|
+
# draw rectangle on all detected blobs
|
|
18
|
+
blobs.each {|b| image.draw_rectangle(b.left,b.top,b.left+b.width-1,b.top+b.height-1,cam_rgb(255,0,0))}
|
|
19
|
+
# save the resulting picture
|
|
20
|
+
image.save_bmp("output/ruby_alfa156_labeling.bmp")
|
|
21
|
+
# find out the biggest blob
|
|
22
|
+
sorted=blobs.sort {|a,b| b.surface<=>a.surface}
|
|
23
|
+
puts "The bigger blob is at position (#{sorted[0].cx},#{sorted[0].cy}) and its surface is #{sorted[0].surface}"
|
|
24
|
+
# assertions
|
|
25
|
+
assert_equal(blobs.nb_blobs,12)
|
|
26
|
+
assert_equal(sorted[0].cx,170)
|
|
27
|
+
assert_equal(sorted[0].cy,128)
|
|
28
|
+
assert_equal(sorted[0].surface,601)
|
|
29
|
+
end
|
|
30
|
+
end
|
data/test/test_mask.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'lib/camellia'
|
|
3
|
+
include Camellia
|
|
4
|
+
class TestMask < Test::Unit::TestCase
|
|
5
|
+
def test_mask
|
|
6
|
+
source=CamImage.new
|
|
7
|
+
# load picture chess.pgm
|
|
8
|
+
source.load_pgm("resources/chess.pgm")
|
|
9
|
+
mask=CamImage.new(source.width,source.height)
|
|
10
|
+
# draw a filled circle in mask
|
|
11
|
+
mask.set!(0)
|
|
12
|
+
mask.draw_circle(mask.width/2,mask.height/2,50,255)
|
|
13
|
+
n=mask.fill_color(mask.width/2,mask.height/2,255)
|
|
14
|
+
assert_equal(n,7837) # number of pixels filled with color
|
|
15
|
+
# encode the mask and associate it to the source image
|
|
16
|
+
encoded_mask=mask.encode
|
|
17
|
+
source.mask=encoded_mask
|
|
18
|
+
encoded_mask.inverse!
|
|
19
|
+
dest=CamImage.new
|
|
20
|
+
source.copy(dest) # copies only the mask! not like dup or clone!
|
|
21
|
+
# and then compute a sobel inside
|
|
22
|
+
encoded_mask.inverse!
|
|
23
|
+
b=source.sobel_v_abs(dest) # sobel only on the mask
|
|
24
|
+
dest.save_pgm("output/ruby_chess_sobel_mask.pgm")
|
|
25
|
+
# checking types
|
|
26
|
+
assert_equal(source.class,Camellia::CamImage)
|
|
27
|
+
assert_equal(encoded_mask.class,Camellia::CamRLEImage)
|
|
28
|
+
|
|
29
|
+
# use a non compressed mask
|
|
30
|
+
source.mask=mask
|
|
31
|
+
source.set!(0)
|
|
32
|
+
source.save_pgm("output/ruby_chess_hole.pgm");
|
|
33
|
+
end
|
|
34
|
+
end
|