├── README.md
├── accept_solution.m
├── bi2de.m
├── convert_thresholds.m
├── crossover.m
├── crossover_one.m
├── first_best.m
├── fitness.m
├── fitness_one.m
├── ga_segmentation.m
├── images
├── cameraman.png
└── img.png
├── initialization.m
├── mutate_one.m
├── mutation.m
└── threshold_bin2dec.m
/README.md:
--------------------------------------------------------------------------------
1 | ## Image Segmentation Using Genetic Algorithm
2 |
3 | Project is inspired by [paper](http://www.worldcomp-proceedings.com/proc/p2011/IPC8346.pdf) ([summary](http://breadthsearch.blogspot.cz/2014/11/multi-thresholding-image-segmentation.html)).
4 | Image segmentation can be pursued by many different ways.
5 | One of them is called multi-thresholding.
6 | Since we want to segment image to more than two segments (more than one threshold) we need to determine at least two thresholds.
7 | If we want to segment gray level image with 256 levels to three segments we are likely supposed to examine 256*255 = 65280 different threshold combinations.
8 | This brute force approach would end up with optimal solution, however computing time would be definitely high.
9 | Genetic algorithm searches space containing all possible solutions and obtain the best solution among all examined in much less time than brute force algorithm.
10 |
11 |
12 |
13 |
14 |
15 | *The result of segmentation by genetic algorithm with population size 20 and number of iterations 30.*
16 |
17 | ## Implementation
18 | Genetic algorithm was implemented in GNU Octave.
19 | This language was selected due to its fast prototyping.
20 | The speed of algorithm is not the matter of interest.
21 |
22 | #### Initialization
23 | This part of code is found at *ga_segmentation.m*.
24 | There are few settings which can affect the result of algorithm.
25 | * **n_population:**
26 | size of population; contains different solutions
27 | * **n_iterations:**
28 | number of iterations; algorithm terminates after all iterations are done
29 | * **n_thresholds:**
30 | number of desired thresholds; n_thresholds = (number of segments - 1)
31 |
32 | The next three settings are related to each other.
33 | They are ratios of selection (**n_selection**), crossover (**n_crossover**) and mutation (**n_mutation**).
34 | The sum of all these parameters has to be equal to 1.
35 | This condition guarantees the size of population does not change between iterations.
36 |
37 | Single chromose is implemented as vector of binary numbers.
38 | The length of vector is *L* * *n*, where *L* denotes *log*(number of gray levels) and *n* is the number of desired thresholds.
39 | Population is represented a matrix, where each row is single chromosome and number of rows corresponds to size of population.
40 | An initial population was randomly generated.
41 |
42 | In this part we also load a image for segmentation.
43 | Algorithm works only with grayscale images, so we always convert each image at the beginning before we start to work with it.
44 |
45 | #### Evaluation of fitness
46 | According to paper, which was mentioned above, evaluation of fitness should be performed with ratio between between inter-object variance and intra-object variance.
47 | We have decided for sligthly easier evaluation based on sum of intra-object variance.
48 | The solution with the lowest sum is the most accurate.
49 |
50 | *fitness.m*, *fitness_one.m*
51 |
52 | #### Selection
53 | Current solution selects to new generation only the best solutions.
54 | The number of forwarded solution depends on ratio **n_selection**.
55 |
56 | *first_best.m*
57 |
58 | #### Crossover
59 | Chromosomes, which are supposed to crossover, are chosen from two vectors containing radomly permutated indexes (numbers of row) of chromosomes.
60 | The number chromosomes, which crossover, depends on ratio **n_crossover**.
61 | One-point crossover is employed in current solution.
62 | The point of crossover is randomly generated with uniform distribution.
63 |
64 | *crossover.m*, *crossover_one.m*
65 |
66 | #### Mutation
67 | Indexes (number of rows) of chromosomes are randomly permutated and the very first of them are more likely to be chosen.
68 | The number of chromosomes, which happens to be chosen for mutation, depends on ratio **n_mutation**.
69 | Current solution allows to mutate only one gene of chromosome.
70 |
71 | *mutation.m*, *mutate_one.m*
72 |
73 | ## Experiments
74 | Two experiments were performed:
75 | * The first one with picture composed from solid colors
76 | * and the second one uses benchmark from website [mosaic.utia.cas.cz](http://mosaic.utia.cas.cz/).
77 |
78 | During the experiment we observed that 20 as size of population and 50 as number of iterations are satisfying for most of cases.
79 |
80 | #### Solid colors
81 | Though segmentation of this picture looks promising, we were not able to successfully segment all parts.
82 | The best result can be shown at the end of this subsection.
83 | We also noticed that algorithm is prone to insignificant segments (edges of shapes) with small area.
84 |
85 |
86 |
87 | *Source image contains 8 different colors.*
88 |
89 |
90 |
91 |
92 |
93 | *2 thresholds, 3 segments.*
94 |
95 |
96 |
97 | *10 thresholds, 11 segments.*
98 |
99 | #### Benchmark
100 | Benchmark consist from 20 different images with artificially created texture segments.
101 | The number of segments is between 3 and 12, which can be sometimes even challenging for human.
102 |
103 | Each triplet of images below represents source image, ground truth of segmentation and segmentation done by genetic algorithm.
104 | As we could expect the results have not reached high.
105 | Correct segmentation is 2.17 % overall.
106 |
107 |
108 |
109 |
110 |
111 | *2 thresholds, 3 segments.*
112 |
113 |
114 |
115 |
116 |
117 | *11 thresholds, 12 segments.*
118 |
119 | ## Conclusion
120 | Genetic algorithm is able to find suboptiomal solution of multi-threshold segmentation.
121 | This solution is not suitable for all kinds of segmentation problems; e.g. binary segmentation: there are more reliable methods like Balanced histogram thresholding or Otsu's method.
122 | The low performance of texture segmentation was confirmed by benchmark.
123 |
124 | The shortcoming of implemented solution is propensity to segment small areas like edges.
125 | These areas are not essential in segmentation and therefore should not taken into account.
126 |
127 | The algorithm could be refined by two-point crossover or roulette wheel for selecting chromosomes to the next population.
128 |
--------------------------------------------------------------------------------
/accept_solution.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 | % Employs the best solution and displays segments of examined image.
6 |
7 | function accept_solution(image, population, n_thresholds)
8 |
9 | segmentation = zeros(size(image));
10 | segmentation_value = 1/n_thresholds;
11 | genome_size = size(population, 2)/n_thresholds;
12 |
13 | % Retrieve the best solution
14 | [b, b_i] = sort(fitness(image, population, n_thresholds));
15 | best_genome = population(b_i(1),:);
16 |
17 | threshold = sort(threshold_bin2dec(best_genome, n_thresholds));
18 |
19 | value = 0;
20 | end_i = size(threshold, 2) + 1;
21 | for i = 1:end_i
22 | if (i == 1)
23 | % The first threshold
24 | left = 0;
25 | right = threshold(i);
26 | elseif (i == end_i)
27 | % The last threshold
28 | left = threshold(i-1);
29 | right = max(image(:));
30 | else
31 | % Regular threshold
32 | left = threshold(i-1);
33 | right = threshold(i);
34 | endif
35 |
36 | % <0; x) = left;
38 | right_mask = image < right;
39 | mask = left_mask .* right_mask;
40 |
41 | segmentation += value*mask;
42 |
43 | % Display segments
44 | %if (i >= 2)
45 | % figure
46 | % mask_value = value*mask;
47 | % imshow(mask_value);
48 | % imwrite(mask_value, strcat(num2str(i), ".png"));
49 | %endif
50 |
51 | value += segmentation_value;
52 | endfor
53 |
54 | imshow(segmentation);
55 |
56 | endfunction
57 |
--------------------------------------------------------------------------------
/bi2de.m:
--------------------------------------------------------------------------------
1 | ## Copyright (C) 2001 Laurent Mazet
2 | ##
3 | ## This program is free software; you can redistribute it and/or modify
4 | ## it under the terms of the GNU General Public License as published by
5 | ## the Free Software Foundation; either version 2 of the License, or
6 | ## (at your option) any later version.
7 | ##
8 | ## This program is distributed in the hope that it will be useful,
9 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | ## GNU General Public License for more details.
12 | ##
13 | ## You should have received a copy of the GNU General Public License
14 | ## along with this program; if not, write to the Free Software
15 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 |
17 | ## -*- texinfo -*-
18 | ## @deftypefn {Function File} {@var{d} = } bi2de (@var{b})
19 | ## @deftypefnx {Function File} {@var{d} = } bi2de (@var{b},@var{p})
20 | ## @deftypefnx {Function File} {@var{d} = } bi2de (@var{b},@var{p},@var{f})
21 | ##
22 | ## Convert bit matrix to a vector of integers
23 | ##
24 | ## Each row of the matrix @var{b} is treated as a single integer represented
25 | ## in binary form. The elements of @var{b}, must therefore be '0' or '1'
26 | ##
27 | ## If @var{p} is defined then it is treated as the base of the decomposition
28 | ## and the elements of @var{b} must then lie between '0' and 'p-1'.
29 | ##
30 | ## The variable @var{f} defines whether the first or last element of @var{b}
31 | ## is considered to be the most-significant. Valid values of @var{f} are
32 | ## 'right-msb' or 'left-msb'. By default @var{f} is 'right-msb'.
33 | ## @end deftypefn
34 | ## @seealso{de2bi}
35 |
36 | ## 2001-02-02
37 | ## initial release
38 | ## 2003-02-02
39 | ## add orientation of b and help in texinfo
40 |
41 | function d = bi2de (b, p, f)
42 |
43 | switch (nargin)
44 | case 1,
45 | p = 2;
46 | f = 'right-msb';
47 | case 2,
48 | if (isstr(p))
49 | f = p;
50 | p = 2;
51 | else
52 | f = 'right-msb';
53 | endif
54 | case 3,
55 | if (isstr(p))
56 | tmp = f;
57 | f = p;
58 | p = tmp;
59 | endif
60 | otherwise
61 | error ("usage: d = bi2de (b, [p])");
62 | endswitch
63 |
64 | if ( any (b (:) < 0) || any (b (:) > p - 1) )
65 | error ("bi2de: d must only contain value in [0, p-1]");
66 | endif
67 |
68 | if (strcmp(f,'left-msb'))
69 | b = b(:,size(b,2):-1:1);
70 | elseif (!strcmp(f,'right-msb'))
71 | error("bi2de: unrecognized flag");
72 | endif
73 |
74 | if (length (b) == 0)
75 | d = [];
76 | else
77 | d = b * ( p .^ [ 0 : (columns(b)-1) ]' );
78 | endif
79 |
80 | endfunction;
81 |
--------------------------------------------------------------------------------
/convert_thresholds.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/26/2014
4 | %
5 | % Converts binary thresholds of all population to decimal representation.
6 |
7 | function thresholds = convert_thresholds(population, n_thresholds)
8 |
9 | thresholds = [];
10 | population_size = size(population, 1);
11 |
12 | for i = 1:population_size
13 | thresholds = [thresholds; threshold_bin2dec(population(i,:), n_thresholds)];
14 | endfor
15 |
16 | endfunction
17 |
--------------------------------------------------------------------------------
/crossover.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 | % Crossovers desired part of population.
6 |
7 | function new_population = crossover(population, p_crossover, new_population)
8 |
9 | population_size = size(population, 1);
10 |
11 | % Random permutation of genomes order
12 | parent_first = randperm(population_size);
13 | parent_second = randperm(population_size);
14 |
15 | % Number of couples used for crossover
16 | n_crossovers = round(p_crossover*population_size)/2;
17 |
18 | for i = 1:n_crossovers
19 | % Crossovers parents
20 | [desc_first desc_second] = crossover_one(population(parent_first(i), :), ...
21 | population(parent_second(i), :));
22 |
23 | % Add crossover descendants
24 | new_population = [new_population; desc_first; desc_second];
25 | endfor
26 |
27 | endfunction
28 |
--------------------------------------------------------------------------------
/crossover_one.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 | % Crossover of two parents creating new descendants by one-point crossover.
6 |
7 | function [desc_first desc_second] = crossover_one(parent_first, parent_second)
8 |
9 | parent_size = size(parent_first, 2);
10 |
11 | % Randomly generated number between 1 and the length of parent's genome.
12 | point = round(unifrnd(1, parent_size-1));
13 |
14 | % Crossover
15 | desc_first = [parent_first(1:point) parent_second(point+1:parent_size)];
16 | desc_second = [parent_second(1:point) parent_first(point+1:parent_size)];
17 |
18 | endfunction
19 |
--------------------------------------------------------------------------------
/first_best.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 | % Selecting the first best solutions from current population and
6 | % transfering to new population.
7 |
8 | function new_population = first_best(ranking, population, p_selection, new_population)
9 |
10 | population_size = size(population, 1);
11 | [best, best_i] = sort(ranking);
12 |
13 | for i = 1:round(p_selection*population_size)
14 | new_population = [new_population; population(best_i(i), :)];
15 | endfor
16 |
17 | endfunction
18 |
--------------------------------------------------------------------------------
/fitness.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/26/2014
4 | %
5 | % Computes fitness ranking for all population.
6 |
7 | function ranking = fitness(image, population, n_thresholds)
8 |
9 | ranking = [];
10 |
11 | % Convert thresholds to decimal representation
12 | thresholds = convert_thresholds(population, n_thresholds);
13 |
14 | % Vectorize image
15 | image_vec = image(:);
16 |
17 | % Computes fitness ranking for all thresholds in population
18 | for i = 1:size(thresholds, 1)
19 | ranking = [ranking; fitness_one(image_vec, thresholds(i,:))];
20 | endfor
21 |
22 | endfunction
23 |
--------------------------------------------------------------------------------
/fitness_one.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/26/2014
4 | %
5 | % Computes fitness ranking for given chromosome.
6 |
7 | function ranking = fitness_one(image_vec, thresholds_vec)
8 |
9 | ranking = 1;
10 | inter_var = 0;
11 | intra_var = 0; % TODO implement
12 |
13 | % Sort thresholds
14 | thresholds_vec = sort(thresholds_vec);
15 |
16 | end_i = size(thresholds_vec, 2) + 1;
17 | for i = 1:end_i
18 | if ((i == 1 && end_i == 2) || i == 1)
19 | % One threshold or the first threshold
20 | left = 0;
21 | right = thresholds_vec(i);
22 | elseif (i == end_i)
23 | % The last threshold
24 | left = thresholds_vec(i-1);
25 | right = max(image_vec);
26 | else
27 | % More thresholds
28 | left = thresholds_vec(i-1);
29 | right = thresholds_vec(i);
30 | endif
31 |
32 | % <0; x) = left;
34 | right_mask = image_vec < right;
35 | mask = left_mask .* right_mask;
36 | object = image_vec(find(mask));
37 |
38 | % TODO better way to relate all variances within objects?
39 | if (length(object) == 0)
40 | variance = 1;
41 | else
42 | variance = var(object);
43 | endif
44 |
45 | ranking = ranking + variance;
46 | endfor
47 |
48 | endfunction
49 |
--------------------------------------------------------------------------------
/ga_segmentation.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/24/2014
4 |
5 | pkg load image
6 |
7 | % Default variables
8 | n_population = 20;
9 | n_iterations = 50;
10 | n_bins = 256;
11 | n_thresholds = 5;
12 |
13 | % Ratios of all GA operations
14 | p_selection = 0.1;
15 | p_crossover = 0.8;
16 | p_mutation = 0.1;
17 | assert(sum([p_selection, p_crossover, p_mutation]) == 1, 'Total sum of proportions have to be 1!');
18 |
19 | % Read image
20 | image = imread("images/img.png");
21 |
22 | % Convert image to gray levels
23 | if (size(image, 3) == 3)
24 | image_gray = rgb2gray(image);
25 | else
26 | image_gray = image;
27 | endif
28 |
29 | % Initialization
30 | population = initialization(n_population, n_bins, n_thresholds);
31 |
32 | for i = 1:n_iterations
33 | new_population = [];
34 |
35 | % Evaluation of fitness
36 | ranking = fitness(image, population, n_thresholds);
37 |
38 | %% Reproduction
39 | % Selection
40 | % TODO create more strategies (like roulette wheel)
41 | new_population = first_best(ranking, population, p_selection, new_population);
42 |
43 | % Crossover
44 | new_population = crossover(population, p_crossover, new_population);
45 |
46 | % Mutation
47 | new_population = mutation(population, p_mutation, new_population);
48 |
49 | population = new_population;
50 | endfor
51 |
52 | % Accepting the solution
53 | accept_solution(image_gray, population, n_thresholds);
54 |
--------------------------------------------------------------------------------
/images/cameraman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/martinkersner/Image-Segmentation-Using-Genetic-Algorithm/c410a7201cf13fdb4907d1aff5596890cf76fc0a/images/cameraman.png
--------------------------------------------------------------------------------
/images/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/martinkersner/Image-Segmentation-Using-Genetic-Algorithm/c410a7201cf13fdb4907d1aff5596890cf76fc0a/images/img.png
--------------------------------------------------------------------------------
/initialization.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/26/2014
4 | %
5 | % Randomly generates the first population.
6 |
7 | function population = initialization(n_population, n_bins, n_thresholds)
8 |
9 | population = round(unifrnd(0, 1, [n_population ceil(log2(n_bins))*n_thresholds]));
10 |
11 | endfunction
12 |
--------------------------------------------------------------------------------
/mutate_one.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 | % Mutates given chromose at one randomly generated position.
6 |
7 | function new_chromosome = mutate_one(chromosome)
8 |
9 | new_chromosome = chromosome;
10 |
11 | chromosome_size = size(chromosome, 2);
12 | gene = round(unifrnd(1, chromosome_size));
13 |
14 | % Mutate one gene
15 | if (chromosome(gene) == 1)
16 | new_chromosome(gene) = 0;
17 | else
18 | new_chromosome(gene) = 1;
19 | endif
20 |
21 | endfunction
22 |
--------------------------------------------------------------------------------
/mutation.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 |
6 | function new_population = mutation(population, p_mutation, new_population)
7 |
8 | population_size = size(population, 1);
9 |
10 | % Random permutation of genomes order
11 | mutation_order = randperm(population_size);
12 |
13 | for i = 1:round(p_mutation*population_size);
14 | new_population = [new_population; mutate_one(population(mutation_order(i), :))];
15 | endfor
16 |
17 | endfunction
18 |
--------------------------------------------------------------------------------
/threshold_bin2dec.m:
--------------------------------------------------------------------------------
1 | % MULTI-THRESHOLDING IMAGE SEGMENTATION USING GENETIC ALGORITHMS
2 | % Martin Kersner,
3 | % 11/27/2014
4 | %
5 | % Converts thresholds of one genome from binary to decimal format.
6 |
7 | function dec_thresholds = threshold_bin2dec(bin_thresholds, n_thresholds)
8 |
9 | dec_thresholds = [];
10 | threshold_length = (size(bin_thresholds, 2)/n_thresholds);
11 |
12 | for i = 1:threshold_length:size(bin_thresholds, 2)
13 | dec_thresholds = [dec_thresholds, bi2de(bin_thresholds(i:i+threshold_length-1))];
14 | endfor
15 |
16 | endfunction
17 |
--------------------------------------------------------------------------------