├── LICENSE ├── deeplearning-keras-workshop.zip ├── how-BioNTechPfizer-SARS-CoV-2-vaccine-works ├── assets │ ├── 0_0YAoXqr2cQvtKgkw.jpg │ ├── BNT162b2 mRNA.png │ ├── BioXp-printer.png │ ├── Protein_translation.gif │ ├── Schematic.png │ ├── rna-codon-table.png │ ├── sars-em.jpg │ ├── seq.png │ ├── seqe.png │ ├── seqr.png │ ├── seqv.png │ └── vaccine.png └── واکسن کرونای فایزر چطور کار می‌کند؟.docx ├── how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning ├── Break CAPTCHA │ ├── CNN │ │ ├── cnn.h │ │ ├── conv_layer_t.h │ │ ├── dropout_layer_t.h │ │ ├── fc_layer.h │ │ ├── gradient_t.h │ │ ├── layer_t.h │ │ ├── optimization_method.h │ │ ├── point_t.h │ │ ├── pool_layer_t.h │ │ ├── relu_layer_t.h │ │ ├── tensor_t.h │ │ └── types.h │ ├── Captcha Break.cpp │ ├── byteswap.h │ └── download.sh ├── assets │ ├── CAPTCHA Diag1.png │ ├── CAPTCHA Sample │ │ ├── 0.gif │ │ ├── 1.gif │ │ ├── 10.gif │ │ ├── 11.gif │ │ ├── 12.gif │ │ ├── 13.gif │ │ ├── 14.gif │ │ ├── 15.gif │ │ ├── 16.gif │ │ ├── 17.gif │ │ ├── 18.gif │ │ ├── 19.gif │ │ ├── 2.gif │ │ ├── 20.gif │ │ ├── 21.gif │ │ ├── 22.gif │ │ ├── 23.gif │ │ ├── 24.gif │ │ ├── 26.gif │ │ ├── 28.gif │ │ ├── 3.gif │ │ ├── 33.gif │ │ ├── 4.gif │ │ ├── 5.gif │ │ ├── 6.gif │ │ ├── 7.gif │ │ ├── 8.gif │ │ └── 9.gif │ ├── CNN Network.png │ ├── Golestan Page.png │ ├── Header.png │ ├── Image processing.png │ ├── after k means.png │ ├── dataset.png │ ├── google recaptcha.gif │ ├── hist1.png │ └── tweet.gif ├── blog post.txt └── چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟---kukzjnwwsqdx.html ├── how-to-build-an-intelligent-car-with-image-processing ├── Intelligent Car │ ├── Intelligent Car.cpp │ ├── cansniffer.cs │ ├── client.cpp │ └── serveur.cpp ├── assets │ ├── 4.png │ ├── BCM Map.png │ ├── BCM.png │ ├── Capture Video.gif │ ├── Header.png │ ├── Hough Transform out.png │ ├── Lamp Schematic.png │ ├── Rana Nodes.png │ ├── Road Sample │ │ ├── Sample1.png │ │ ├── Sample10.png │ │ ├── Sample2.png │ │ ├── Sample3.png │ │ ├── Sample3_ref.png │ │ ├── Sample4.png │ │ ├── Sample5.png │ │ ├── Sample6.png │ │ ├── Sample6_ref.png │ │ ├── Sample7.png │ │ ├── Sample8.png │ │ └── Sample9.png │ ├── T Connector.png │ ├── alarm.png │ ├── can format.png │ ├── canny edge detector out.png │ ├── cansniffer.gif │ ├── car.png │ ├── convert to gray and crop.png │ ├── edge sample in our images.png │ ├── hough-mb_parameter_space.png │ ├── inRange bitwise_or.png │ ├── line finding.png │ ├── output sample for day and night.png │ ├── reference line detection.png │ ├── sendFrame.gif │ ├── solidWhiteRight.mp4 │ ├── solidYellowLeft.mp4 │ ├── twitter.png │ └── waymo.jpeg ├── blog post.txt ├── documents │ ├── 206_Multiplex_Intro.pdf │ ├── Emdad_Rana_Peugeot206_New.pdf │ ├── IKCO_Rana_Multiplex_Nodes_Configuration_Manual.pdf │ ├── IKCO_Rana_officialBooklet.pdf │ ├── ISACO_IKCO_NewMUX_SAMAND_RANA_DENA_PARS_Manual.pdf │ ├── Introduction to the Controller Area Network (CAN).pdf │ ├── MultiPlex_Samand_Soren_Rana_206_EmdadKhodro.pdf │ └── TPCAN 207 Sport pack.pdf └── هک خودرو؛ چطوری با پردازش تصویر خودرومونو هوشمند کنیم؟---rkgz4q8v37xg.html ├── how-to-find-airplane-in-images ├── 2020-11-18-----چطوری با بینایی کامپیوتر هواپی---pr9tj8klkiiu.html ├── assets │ ├── FindPhotosFaster.png │ ├── acc_table.png │ ├── cover.png │ ├── dataset_airplane.png │ ├── dataset_nonairplane.png │ ├── full_conv_model.png │ ├── fullimage_tiles_processing.png │ ├── generated_samples.png │ ├── hoda_sample.png │ ├── max-pooled_array.png │ ├── model.png │ ├── nn_model_center.png │ ├── nn_model_toppng.png │ ├── nn_model_win.gif │ ├── nn_model_win1.png │ ├── nn_model_win10.png │ ├── nn_model_win11.png │ ├── nn_model_win2.png │ ├── nn_model_win3.png │ ├── nn_model_win4.png │ ├── nn_model_win5.png │ ├── nn_model_win6.png │ ├── nn_model_win7.png │ ├── nn_model_win8.png │ ├── nn_model_win9.png │ ├── num_gif.gif │ ├── num_img.png │ ├── num_num.png │ ├── num_num_grid.png │ ├── num_zeros.png │ ├── pic.JPG │ ├── pic_conv.png │ ├── sample_faltten.png │ ├── sample_faltten_zero.png │ ├── sample_sat_img.png │ ├── sample_six.png │ ├── sample_three.png │ ├── tile_conv_processing.png │ ├── training_charts.png │ ├── tweet.png │ └── yolo.png ├── blog post.txt └── how_to_find_airplanes_in_images.ipynb ├── introduction-to-deep-learning-with-keras-workshop ├── 01_Introduction_to_Deep_Learning_with_Keras_Workshop.ipynb ├── 02.Introduction to Deep Learning with Keras Workshop_CNN.ipynb └── 03.Introduction to Deep Learning with Keras Workshop_cat_vs_dog.ipynb └── readme.md /deeplearning-keras-workshop.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/deeplearning-keras-workshop.zip -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/0_0YAoXqr2cQvtKgkw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/0_0YAoXqr2cQvtKgkw.jpg -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/BNT162b2 mRNA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/BNT162b2 mRNA.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/BioXp-printer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/BioXp-printer.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/Protein_translation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/Protein_translation.gif -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/Schematic.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/rna-codon-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/rna-codon-table.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/sars-em.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/sars-em.jpg -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seq.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seqe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seqe.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seqr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seqr.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seqv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/seqv.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/vaccine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/assets/vaccine.png -------------------------------------------------------------------------------- /how-BioNTechPfizer-SARS-CoV-2-vaccine-works/واکسن کرونای فایزر چطور کار می‌کند؟.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-BioNTechPfizer-SARS-CoV-2-vaccine-works/واکسن کرونای فایزر چطور کار می‌کند؟.docx -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/cnn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tensor_t.h" 3 | #include "optimization_method.h" 4 | #include "fc_layer.h" 5 | #include "pool_layer_t.h" 6 | #include "relu_layer_t.h" 7 | #include "conv_layer_t.h" 8 | #include "dropout_layer_t.h" 9 | 10 | static void calc_grads( layer_t* layer, tensor_t& grad_next_layer ) 11 | { 12 | switch ( layer->type ) 13 | { 14 | case layer_type::conv: 15 | ((conv_layer_t*)layer)->calc_grads( grad_next_layer ); 16 | return; 17 | case layer_type::relu: 18 | ((relu_layer_t*)layer)->calc_grads( grad_next_layer ); 19 | return; 20 | case layer_type::fc: 21 | ((fc_layer_t*)layer)->calc_grads( grad_next_layer ); 22 | return; 23 | case layer_type::pool: 24 | ((pool_layer_t*)layer)->calc_grads( grad_next_layer ); 25 | return; 26 | case layer_type::dropout_layer: 27 | ((dropout_layer_t*)layer)->calc_grads( grad_next_layer ); 28 | return; 29 | default: 30 | assert( false ); 31 | } 32 | } 33 | 34 | static void fix_weights( layer_t* layer ) 35 | { 36 | switch ( layer->type ) 37 | { 38 | case layer_type::conv: 39 | ((conv_layer_t*)layer)->fix_weights(); 40 | return; 41 | case layer_type::relu: 42 | ((relu_layer_t*)layer)->fix_weights(); 43 | return; 44 | case layer_type::fc: 45 | ((fc_layer_t*)layer)->fix_weights(); 46 | return; 47 | case layer_type::pool: 48 | ((pool_layer_t*)layer)->fix_weights(); 49 | return; 50 | case layer_type::dropout_layer: 51 | ((dropout_layer_t*)layer)->fix_weights(); 52 | return; 53 | default: 54 | assert( false ); 55 | } 56 | } 57 | 58 | static void activate( layer_t* layer, tensor_t& in ) 59 | { 60 | switch ( layer->type ) 61 | { 62 | case layer_type::conv: 63 | ((conv_layer_t*)layer)->activate( in ); 64 | return; 65 | case layer_type::relu: 66 | ((relu_layer_t*)layer)->activate( in ); 67 | return; 68 | case layer_type::fc: 69 | ((fc_layer_t*)layer)->activate( in ); 70 | return; 71 | case layer_type::pool: 72 | ((pool_layer_t*)layer)->activate( in ); 73 | return; 74 | case layer_type::dropout_layer: 75 | ((dropout_layer_t*)layer)->activate( in ); 76 | return; 77 | default: 78 | assert( false ); 79 | } 80 | } -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/conv_layer_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "layer_t.h" 3 | 4 | #pragma pack(push, 1) 5 | struct conv_layer_t 6 | { 7 | layer_type type = layer_type::conv; 8 | tensor_t grads_in; 9 | tensor_t in; 10 | tensor_t out; 11 | std::vector> filters; 12 | std::vector> filter_grads; 13 | uint16_t stride; 14 | uint16_t extend_filter; 15 | 16 | conv_layer_t( uint16_t stride, uint16_t extend_filter, uint16_t number_filters, tdsize in_size ) 17 | : 18 | grads_in( in_size.x, in_size.y, in_size.z ), 19 | in( in_size.x, in_size.y, in_size.z ), 20 | out( 21 | (in_size.x - extend_filter) / stride + 1, 22 | (in_size.y - extend_filter) / stride + 1, 23 | number_filters 24 | ) 25 | 26 | { 27 | this->stride = stride; 28 | this->extend_filter = extend_filter; 29 | assert( (float( in_size.x - extend_filter ) / stride + 1) 30 | == 31 | ((in_size.x - extend_filter) / stride + 1) ); 32 | 33 | assert( (float( in_size.y - extend_filter ) / stride + 1) 34 | == 35 | ((in_size.y - extend_filter) / stride + 1) ); 36 | 37 | for ( int a = 0; a < number_filters; a++ ) 38 | { 39 | tensor_t t( extend_filter, extend_filter, in_size.z ); 40 | 41 | int maxval = extend_filter * extend_filter * in_size.z; 42 | 43 | for ( int i = 0; i < extend_filter; i++ ) 44 | for ( int j = 0; j < extend_filter; j++ ) 45 | for ( int z = 0; z < in_size.z; z++ ) 46 | t( i, j, z ) = 1.0f / maxval * rand() / float( RAND_MAX ); 47 | filters.push_back( t ); 48 | } 49 | for ( int i = 0; i < number_filters; i++ ) 50 | { 51 | tensor_t t( extend_filter, extend_filter, in_size.z ); 52 | filter_grads.push_back( t ); 53 | } 54 | 55 | } 56 | 57 | point_t map_to_input( point_t out, int z ) 58 | { 59 | out.x *= stride; 60 | out.y *= stride; 61 | out.z = z; 62 | return out; 63 | } 64 | 65 | struct range_t 66 | { 67 | int min_x, min_y, min_z; 68 | int max_x, max_y, max_z; 69 | }; 70 | 71 | int normalize_range( float f, int max, bool lim_min ) 72 | { 73 | if ( f <= 0 ) 74 | return 0; 75 | max -= 1; 76 | if ( f >= max ) 77 | return max; 78 | 79 | if ( lim_min ) // left side of inequality 80 | return ceil( f ); 81 | else 82 | return floor( f ); 83 | } 84 | 85 | range_t map_to_output( int x, int y ) 86 | { 87 | float a = x; 88 | float b = y; 89 | return 90 | { 91 | normalize_range( (a - extend_filter + 1) / stride, out.size.x, true ), 92 | normalize_range( (b - extend_filter + 1) / stride, out.size.y, true ), 93 | 0, 94 | normalize_range( a / stride, out.size.x, false ), 95 | normalize_range( b / stride, out.size.y, false ), 96 | (int)filters.size() - 1, 97 | }; 98 | } 99 | 100 | void activate( tensor_t& in ) 101 | { 102 | this->in = in; 103 | activate(); 104 | } 105 | 106 | void activate() 107 | { 108 | for ( int filter = 0; filter < filters.size(); filter++ ) 109 | { 110 | tensor_t& filter_data = filters[filter]; 111 | for ( int x = 0; x < out.size.x; x++ ) 112 | { 113 | for ( int y = 0; y < out.size.y; y++ ) 114 | { 115 | point_t mapped = map_to_input( { (uint16_t)x, (uint16_t)y, 0 }, 0 ); 116 | float sum = 0; 117 | for ( int i = 0; i < extend_filter; i++ ) 118 | for ( int j = 0; j < extend_filter; j++ ) 119 | for ( int z = 0; z < in.size.z; z++ ) 120 | { 121 | float f = filter_data( i, j, z ); 122 | float v = in( mapped.x + i, mapped.y + j, z ); 123 | sum += f*v; 124 | } 125 | out( x, y, filter ) = sum; 126 | } 127 | } 128 | } 129 | } 130 | 131 | void fix_weights() 132 | { 133 | for ( int a = 0; a < filters.size(); a++ ) 134 | for ( int i = 0; i < extend_filter; i++ ) 135 | for ( int j = 0; j < extend_filter; j++ ) 136 | for ( int z = 0; z < in.size.z; z++ ) 137 | { 138 | float& w = filters[a].get( i, j, z ); 139 | gradient_t& grad = filter_grads[a].get( i, j, z ); 140 | w = update_weight( w, grad ); 141 | update_gradient( grad ); 142 | } 143 | } 144 | 145 | void calc_grads( tensor_t& grad_next_layer ) 146 | { 147 | 148 | for ( int k = 0; k < filter_grads.size(); k++ ) 149 | { 150 | for ( int i = 0; i < extend_filter; i++ ) 151 | for ( int j = 0; j < extend_filter; j++ ) 152 | for ( int z = 0; z < in.size.z; z++ ) 153 | filter_grads[k].get( i, j, z ).grad = 0; 154 | } 155 | 156 | for ( int x = 0; x < in.size.x; x++ ) 157 | { 158 | for ( int y = 0; y < in.size.y; y++ ) 159 | { 160 | range_t rn = map_to_output( x, y ); 161 | for ( int z = 0; z < in.size.z; z++ ) 162 | { 163 | float sum_error = 0; 164 | for ( int i = rn.min_x; i <= rn.max_x; i++ ) 165 | { 166 | int minx = i * stride; 167 | for ( int j = rn.min_y; j <= rn.max_y; j++ ) 168 | { 169 | int miny = j * stride; 170 | for ( int k = rn.min_z; k <= rn.max_z; k++ ) 171 | { 172 | int w_applied = filters[k].get( x - minx, y - miny, z ); 173 | sum_error += w_applied * grad_next_layer( i, j, k ); 174 | filter_grads[k].get( x - minx, y - miny, z ).grad += in( x, y, z ) * grad_next_layer( i, j, k ); 175 | } 176 | } 177 | } 178 | grads_in( x, y, z ) = sum_error; 179 | } 180 | } 181 | } 182 | } 183 | }; 184 | #pragma pack(pop) -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/dropout_layer_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "layer_t.h" 3 | 4 | #pragma pack(push, 1) 5 | struct dropout_layer_t 6 | { 7 | layer_type type = layer_type::dropout_layer; 8 | tensor_t grads_in; 9 | tensor_t in; 10 | tensor_t out; 11 | tensor_t hitmap; 12 | float p_activation; 13 | 14 | dropout_layer_t( tdsize in_size, float p_activation ) 15 | : 16 | in( in_size.x, in_size.y, in_size.z ), 17 | out( in_size.x, in_size.y, in_size.z ), 18 | hitmap( in_size.x, in_size.y, in_size.z ), 19 | grads_in( in_size.x, in_size.y, in_size.z ), 20 | p_activation( p_activation ) 21 | { 22 | 23 | } 24 | 25 | void activate( tensor_t& in ) 26 | { 27 | this->in = in; 28 | activate(); 29 | } 30 | 31 | void activate() 32 | { 33 | for ( int i = 0; i < in.size.x*in.size.y*in.size.z; i++ ) 34 | { 35 | bool active = (rand() % RAND_MAX) / float( RAND_MAX ) <= p_activation; 36 | hitmap.data[i] = active; 37 | out.data[i] = active ? in.data[i] : 0.0f; 38 | } 39 | } 40 | 41 | 42 | void fix_weights() 43 | { 44 | 45 | } 46 | 47 | void calc_grads( tensor_t& grad_next_layer ) 48 | { 49 | for ( int i = 0; i < in.size.x*in.size.y*in.size.z; i++ ) 50 | grads_in.data[i] = hitmap.data[i] ? grad_next_layer.data[i] : 0.0f; 51 | } 52 | }; 53 | #pragma pack(pop) -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/fc_layer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "layer_t.h" 6 | 7 | #pragma pack(push, 1) 8 | struct fc_layer_t 9 | { 10 | layer_type type = layer_type::fc; 11 | tensor_t grads_in; 12 | tensor_t in; 13 | tensor_t out; 14 | std::vector input; 15 | tensor_t weights; 16 | std::vector gradients; 17 | 18 | fc_layer_t( tdsize in_size, int out_size ) 19 | : 20 | in( in_size.x, in_size.y, in_size.z ), 21 | out( out_size, 1, 1 ), 22 | grads_in( in_size.x, in_size.y, in_size.z ), 23 | weights( in_size.x*in_size.y*in_size.z, out_size, 1 ) 24 | { 25 | input = std::vector( out_size ); 26 | gradients = std::vector( out_size ); 27 | 28 | 29 | int maxval = in_size.x * in_size.y * in_size.z; 30 | 31 | for ( int i = 0; i < out_size; i++ ) 32 | for ( int h = 0; h < in_size.x*in_size.y*in_size.z; h++ ) 33 | weights( h, i, 0 ) = 2.19722f / maxval * rand() / float( RAND_MAX ); 34 | // 2.19722f = f^-1(0.9) => x where [1 / (1 + exp(-x) ) = 0.9] 35 | } 36 | 37 | float activator_function( float x ) 38 | { 39 | //return tanhf( x ); 40 | float sig = 1.0f / (1.0f + exp( -x )); 41 | return sig; 42 | } 43 | 44 | float activator_derivative( float x ) 45 | { 46 | //float t = tanhf( x ); 47 | //return 1 - t * t; 48 | float sig = 1.0f / (1.0f + exp( -x )); 49 | return sig * (1 - sig); 50 | } 51 | 52 | void activate( tensor_t& in ) 53 | { 54 | this->in = in; 55 | activate(); 56 | } 57 | 58 | int map( point_t d ) 59 | { 60 | return d.z * (in.size.x * in.size.y) + 61 | d.y * (in.size.x) + 62 | d.x; 63 | } 64 | 65 | void activate() 66 | { 67 | for ( int n = 0; n < out.size.x; n++ ) 68 | { 69 | float inputv = 0; 70 | 71 | for ( int i = 0; i < in.size.x; i++ ) 72 | for ( int j = 0; j < in.size.y; j++ ) 73 | for ( int z = 0; z < in.size.z; z++ ) 74 | { 75 | int m = map( { i, j, z } ); 76 | inputv += in( i, j, z ) * weights( m, n, 0 ); 77 | } 78 | 79 | input[n] = inputv; 80 | 81 | out( n, 0, 0 ) = activator_function( inputv ); 82 | } 83 | } 84 | 85 | void fix_weights() 86 | { 87 | for ( int n = 0; n < out.size.x; n++ ) 88 | { 89 | gradient_t& grad = gradients[n]; 90 | for ( int i = 0; i < in.size.x; i++ ) 91 | for ( int j = 0; j < in.size.y; j++ ) 92 | for ( int z = 0; z < in.size.z; z++ ) 93 | { 94 | int m = map( { i, j, z } ); 95 | float& w = weights( m, n, 0 ); 96 | w = update_weight( w, grad, in( i, j, z ) ); 97 | } 98 | 99 | update_gradient( grad ); 100 | } 101 | } 102 | 103 | void calc_grads( tensor_t& grad_next_layer ) 104 | { 105 | memset( grads_in.data, 0, grads_in.size.x *grads_in.size.y*grads_in.size.z * sizeof( float ) ); 106 | for ( int n = 0; n < out.size.x; n++ ) 107 | { 108 | gradient_t& grad = gradients[n]; 109 | grad.grad = grad_next_layer( n, 0, 0 ) * activator_derivative( input[n] ); 110 | 111 | for ( int i = 0; i < in.size.x; i++ ) 112 | for ( int j = 0; j < in.size.y; j++ ) 113 | for ( int z = 0; z < in.size.z; z++ ) 114 | { 115 | int m = map( { i, j, z } ); 116 | grads_in( i, j, z ) += grad.grad * weights( m, n, 0 ); 117 | } 118 | } 119 | } 120 | }; 121 | #pragma pack(pop) 122 | -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/gradient_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | struct gradient_t 5 | { 6 | float grad; 7 | float oldgrad; 8 | gradient_t() 9 | { 10 | grad = 0; 11 | oldgrad = 0; 12 | } 13 | }; -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/layer_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | #include "tensor_t.h" 4 | 5 | #pragma pack(push, 1) 6 | struct layer_t 7 | { 8 | layer_type type; 9 | tensor_t grads_in; 10 | tensor_t in; 11 | tensor_t out; 12 | }; 13 | #pragma pack(pop) -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/optimization_method.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gradient_t.h" 3 | 4 | #define LEARNING_RATE 0.01 5 | #define MOMENTUM 0.6 6 | #define WEIGHT_DECAY 0.001 7 | 8 | static float update_weight( float w, gradient_t& grad, float multp = 1 ) 9 | { 10 | float m = (grad.grad + grad.oldgrad * MOMENTUM); 11 | w -= LEARNING_RATE * m * multp + 12 | LEARNING_RATE * WEIGHT_DECAY * w; 13 | return w; 14 | } 15 | 16 | static void update_gradient( gradient_t& grad ) 17 | { 18 | grad.oldgrad = (grad.grad + grad.oldgrad * MOMENTUM); 19 | } -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/point_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | struct point_t 3 | { 4 | int x, y, z; 5 | }; 6 | using tdsize = point_t; -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/pool_layer_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "layer_t.h" 3 | 4 | #pragma pack(push, 1) 5 | struct pool_layer_t 6 | { 7 | layer_type type = layer_type::pool; 8 | tensor_t grads_in; 9 | tensor_t in; 10 | tensor_t out; 11 | uint16_t stride; 12 | uint16_t extend_filter; 13 | 14 | pool_layer_t( uint16_t stride, uint16_t extend_filter, tdsize in_size ) 15 | : 16 | grads_in( in_size.x, in_size.y, in_size.z ), 17 | in( in_size.x, in_size.y, in_size.z ), 18 | out( 19 | (in_size.x - extend_filter) / stride + 1, 20 | (in_size.y - extend_filter) / stride + 1, 21 | in_size.z 22 | ) 23 | 24 | { 25 | this->stride = stride; 26 | this->extend_filter = extend_filter; 27 | assert( (float( in_size.x - extend_filter ) / stride + 1) 28 | == 29 | ((in_size.x - extend_filter) / stride + 1) ); 30 | 31 | assert( (float( in_size.y - extend_filter ) / stride + 1) 32 | == 33 | ((in_size.y - extend_filter) / stride + 1) ); 34 | } 35 | 36 | point_t map_to_input( point_t out, int z ) 37 | { 38 | out.x *= stride; 39 | out.y *= stride; 40 | out.z = z; 41 | return out; 42 | } 43 | 44 | struct range_t 45 | { 46 | int min_x, min_y, min_z; 47 | int max_x, max_y, max_z; 48 | }; 49 | 50 | int normalize_range( float f, int max, bool lim_min ) 51 | { 52 | if ( f <= 0 ) 53 | return 0; 54 | max -= 1; 55 | if ( f >= max ) 56 | return max; 57 | 58 | if ( lim_min ) // left side of inequality 59 | return ceil( f ); 60 | else 61 | return floor( f ); 62 | } 63 | 64 | range_t map_to_output( int x, int y ) 65 | { 66 | float a = x; 67 | float b = y; 68 | return 69 | { 70 | normalize_range( (a - extend_filter + 1) / stride, out.size.x, true ), 71 | normalize_range( (b - extend_filter + 1) / stride, out.size.y, true ), 72 | 0, 73 | normalize_range( a / stride, out.size.x, false ), 74 | normalize_range( b / stride, out.size.y, false ), 75 | (int)out.size.z - 1, 76 | }; 77 | } 78 | 79 | void activate( tensor_t& in ) 80 | { 81 | this->in = in; 82 | activate(); 83 | } 84 | 85 | void activate() 86 | { 87 | for ( int x = 0; x < out.size.x; x++ ) 88 | { 89 | for ( int y = 0; y < out.size.y; y++ ) 90 | { 91 | for ( int z = 0; z < out.size.z; z++ ) 92 | { 93 | point_t mapped = map_to_input( { (uint16_t)x, (uint16_t)y, 0 }, 0 ); 94 | float mval = -FLT_MAX; 95 | for ( int i = 0; i < extend_filter; i++ ) 96 | for ( int j = 0; j < extend_filter; j++ ) 97 | { 98 | float v = in( mapped.x + i, mapped.y + j, z ); 99 | if ( v > mval ) 100 | mval = v; 101 | } 102 | out( x, y, z ) = mval; 103 | } 104 | } 105 | } 106 | } 107 | 108 | void fix_weights() 109 | { 110 | 111 | } 112 | 113 | void calc_grads( tensor_t& grad_next_layer ) 114 | { 115 | for ( int x = 0; x < in.size.x; x++ ) 116 | { 117 | for ( int y = 0; y < in.size.y; y++ ) 118 | { 119 | range_t rn = map_to_output( x, y ); 120 | for ( int z = 0; z < in.size.z; z++ ) 121 | { 122 | float sum_error = 0; 123 | for ( int i = rn.min_x; i <= rn.max_x; i++ ) 124 | { 125 | int minx = i * stride; 126 | for ( int j = rn.min_y; j <= rn.max_y; j++ ) 127 | { 128 | int miny = j * stride; 129 | 130 | int is_max = in( x, y, z ) == out( i, j, z ) ? 1 : 0; 131 | sum_error += is_max * grad_next_layer( i, j, z ); 132 | } 133 | } 134 | grads_in( x, y, z ) = sum_error; 135 | } 136 | } 137 | } 138 | } 139 | }; 140 | #pragma pack(pop) -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/relu_layer_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "layer_t.h" 3 | 4 | #pragma pack(push, 1) 5 | struct relu_layer_t 6 | { 7 | layer_type type = layer_type::relu; 8 | tensor_t grads_in; 9 | tensor_t in; 10 | tensor_t out; 11 | 12 | relu_layer_t( tdsize in_size ) 13 | : 14 | in( in_size.x, in_size.y, in_size.z ), 15 | out( in_size.x, in_size.y, in_size.z ), 16 | grads_in( in_size.x, in_size.y, in_size.z ) 17 | { 18 | } 19 | 20 | 21 | void activate( tensor_t& in ) 22 | { 23 | this->in = in; 24 | activate(); 25 | } 26 | 27 | void activate() 28 | { 29 | for ( int i = 0; i < in.size.x; i++ ) 30 | for ( int j = 0; j < in.size.y; j++ ) 31 | for ( int z = 0; z < in.size.z; z++ ) 32 | { 33 | float v = in( i, j, z ); 34 | if ( v < 0 ) 35 | v = 0; 36 | out( i, j, z ) = v; 37 | } 38 | 39 | } 40 | 41 | void fix_weights() 42 | { 43 | 44 | } 45 | 46 | void calc_grads( tensor_t& grad_next_layer ) 47 | { 48 | for ( int i = 0; i < in.size.x; i++ ) 49 | for ( int j = 0; j < in.size.y; j++ ) 50 | for ( int z = 0; z < in.size.z; z++ ) 51 | { 52 | grads_in( i, j, z ) = (in( i, j, z ) < 0) ? 53 | (0) : 54 | (1 * grad_next_layer( i, j, z )); 55 | } 56 | } 57 | }; 58 | #pragma pack(pop) -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/tensor_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "point_t.h" 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct tensor_t 9 | { 10 | T * data; 11 | 12 | tdsize size; 13 | 14 | tensor_t( int _x, int _y, int _z ) 15 | { 16 | data = new T[_x * _y * _z]; 17 | size.x = _x; 18 | size.y = _y; 19 | size.z = _z; 20 | } 21 | 22 | tensor_t( const tensor_t& other ) 23 | { 24 | data = new T[other.size.x *other.size.y *other.size.z]; 25 | memcpy( 26 | this->data, 27 | other.data, 28 | other.size.x *other.size.y *other.size.z * sizeof( T ) 29 | ); 30 | this->size = other.size; 31 | } 32 | 33 | tensor_t operator+( tensor_t& other ) 34 | { 35 | tensor_t clone( *this ); 36 | for ( int i = 0; i < other.size.x * other.size.y * other.size.z; i++ ) 37 | clone.data[i] += other.data[i]; 38 | return clone; 39 | } 40 | 41 | tensor_t operator-( tensor_t& other ) 42 | { 43 | tensor_t clone( *this ); 44 | for ( int i = 0; i < other.size.x * other.size.y * other.size.z; i++ ) 45 | clone.data[i] -= other.data[i]; 46 | return clone; 47 | } 48 | 49 | T& operator()( int _x, int _y, int _z ) 50 | { 51 | return this->get( _x, _y, _z ); 52 | } 53 | 54 | T& get( int _x, int _y, int _z ) 55 | { 56 | assert( _x >= 0 && _y >= 0 && _z >= 0 ); 57 | assert( _x < size.x && _y < size.y && _z < size.z ); 58 | 59 | return data[ 60 | _z * (size.x * size.y) + 61 | _y * (size.x) + 62 | _x 63 | ]; 64 | } 65 | 66 | void copy_from( std::vector>> data ) 67 | { 68 | int z = data.size(); 69 | int y = data[0].size(); 70 | int x = data[0][0].size(); 71 | 72 | for ( int i = 0; i < x; i++ ) 73 | for ( int j = 0; j < y; j++ ) 74 | for ( int k = 0; k < z; k++ ) 75 | get( i, j, k ) = data[k][j][i]; 76 | } 77 | 78 | ~tensor_t() 79 | { 80 | delete[] data; 81 | } 82 | }; 83 | 84 | static void print_tensor( tensor_t& data ) 85 | { 86 | int mx = data.size.x; 87 | int my = data.size.y; 88 | int mz = data.size.z; 89 | 90 | for ( int z = 0; z < mz; z++ ) 91 | { 92 | printf( "[Dim%d]\n", z ); 93 | for ( int y = 0; y < my; y++ ) 94 | { 95 | for ( int x = 0; x < mx; x++ ) 96 | { 97 | printf( "%.2f \t", (float)data.get( x, y, z ) ); 98 | } 99 | printf( "\n" ); 100 | } 101 | } 102 | } 103 | 104 | static tensor_t to_tensor( std::vector>> data ) 105 | { 106 | int z = data.size(); 107 | int y = data[0].size(); 108 | int x = data[0][0].size(); 109 | 110 | 111 | tensor_t t( x, y, z ); 112 | 113 | for ( int i = 0; i < x; i++ ) 114 | for ( int j = 0; j < y; j++ ) 115 | for ( int k = 0; k < z; k++ ) 116 | t( i, j, k ) = data[k][j][i]; 117 | return t; 118 | } 119 | -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/CNN/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class layer_type 4 | { 5 | conv, 6 | fc, 7 | relu, 8 | pool, 9 | dropout_layer 10 | }; -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/Captcha Break.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "byteswap.h" 9 | #include "./CNN/cnn.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace cv; 16 | using namespace std; 17 | using namespace dnn; 18 | 19 | float train(vector& layers, tensor_t& data, tensor_t& expected){ 20 | for (int i = 0; i < layers.size(); i++){ 21 | if (i == 0) 22 | activate(layers[i], data); 23 | else 24 | activate(layers[i], layers[i - 1]->out); 25 | } 26 | 27 | tensor_t grads = layers.back()->out - expected; 28 | 29 | for (int i = layers.size() - 1; i >= 0; i--){ 30 | if (i == layers.size() - 1) 31 | calc_grads(layers[i], grads); 32 | else 33 | calc_grads(layers[i], layers[i + 1]->grads_in); 34 | } 35 | 36 | for (int i = 0; i < layers.size(); i++){ 37 | fix_weights(layers[i]); 38 | } 39 | 40 | float err = 0; 41 | for (int i = 0; i < grads.size.x * grads.size.y * grads.size.z; i++){ 42 | float f = expected.data[i]; 43 | if (f > 0.5) 44 | err += abs(grads.data[i]); 45 | } 46 | return err * 100; 47 | } 48 | 49 | void forward(vector& layers, tensor_t& data){ 50 | for (int i = 0; i < layers.size(); i++){ 51 | if (i == 0) 52 | activate(layers[i], data); 53 | else 54 | activate(layers[i], layers[i - 1]->out); 55 | } 56 | } 57 | 58 | struct case_t{ 59 | tensor_t data; 60 | tensor_t out; 61 | }; 62 | 63 | uint8_t* read_file(const char* szFile){ 64 | ifstream file(szFile, ios::binary | ios::ate); 65 | streamsize size = file.tellg(); 66 | file.seekg(0, ios::beg); 67 | 68 | if (size == -1) 69 | return nullptr; 70 | 71 | uint8_t* buffer = new uint8_t[size]; 72 | file.read((char*)buffer, size); 73 | return buffer; 74 | } 75 | 76 | vector read_test_cases(){ 77 | vector cases; 78 | 79 | uint8_t* train_image = read_file("train-images.idx3-ubyte"); 80 | uint8_t* train_labels = read_file("train-labels.idx1-ubyte"); 81 | 82 | uint32_t case_count = byteswap_uint32(*(uint32_t*)(train_image + 4)); 83 | 84 | for (int i = 0; i < case_count; i++){ 85 | case_t c{ tensor_t(28, 28, 1), tensor_t(10, 1, 1) }; 86 | 87 | uint8_t* img = train_image + 16 + i * (28 * 28); 88 | uint8_t* label = train_labels + 8 + i; 89 | 90 | for (int x = 0; x < 28; x++) 91 | for (int y = 0; y < 28; y++) 92 | c.data(x, y, 0) = img[x + y * 28] / 255.f; 93 | 94 | for (int b = 0; b < 10; b++) 95 | c.out(b, 0, 0) = *label == b ? 1.0f : 0.0f; 96 | cases.push_back(c); 97 | } 98 | delete[] train_image; 99 | delete[] train_labels; 100 | 101 | return cases; 102 | } 103 | 104 | void learnCNN() { 105 | vector cases = read_test_cases(); 106 | vector layers; 107 | 108 | conv_layer_t * layer1 = new conv_layer_t(1, 5, 8, cases[0].data.size); // 28 * 28 * 1 -> 24 * 24 * 8 109 | relu_layer_t * layer2 = new relu_layer_t(layer1->out.size); 110 | pool_layer_t * layer3 = new pool_layer_t(2, 2, layer2->out.size); // 24 * 24 * 8 -> 12 * 12 * 8 111 | fc_layer_t * layer4 = new fc_layer_t(layer3->out.size, 10); // 4 * 4 * 16 -> 10 112 | 113 | layers.push_back((layer_t*)layer1); 114 | layers.push_back((layer_t*)layer2); 115 | layers.push_back((layer_t*)layer3); 116 | layers.push_back((layer_t*)layer4); 117 | 118 | float amse = 0; 119 | int ic = 0; 120 | 121 | for (long ep = 0; ep < 100000; ){ 122 | for (case_t& t : cases){ 123 | float xerr = train(layers, t.data, t.out); 124 | amse += xerr; 125 | 126 | ep++; 127 | ic++; 128 | 129 | if (ep % 1000 == 0) 130 | cout << "case " << ep << " err=" << amse / ic << endl; 131 | } 132 | } 133 | 134 | while (true){ 135 | uint8_t * data = read_file("test.ppm"); 136 | if (data){ 137 | uint8_t * usable = data; 138 | 139 | while (*(uint32_t*)usable != 0x0A353532) 140 | usable++; 141 | 142 | #pragma pack(push, 1) 143 | struct RGB{ 144 | uint8_t r, g, b; 145 | }; 146 | #pragma pack(pop) 147 | 148 | RGB * rgb = (RGB*)usable; 149 | 150 | tensor_t image(28, 28, 1); 151 | for (int i = 0; i < 28; i++){ 152 | for (int j = 0; j < 28; j++){ 153 | RGB rgb_ij = rgb[i * 28 + j]; 154 | image(j, i, 0) = (((float)rgb_ij.r 155 | + rgb_ij.g 156 | + rgb_ij.b) 157 | / (3.0f*255.f)); 158 | } 159 | } 160 | 161 | forward(layers, image); 162 | tensor_t& out = layers.back()->out; 163 | for (int i = 0; i < 10; i++){ 164 | printf("[%i] %f\n", i, out(i, 0, 0)*100.0f); 165 | } 166 | 167 | delete[] data; 168 | } 169 | } 170 | } 171 | 172 | int main(int argc, char** argv){ 173 | // Load image 174 | Mat3b img = imread(".\\assets\\CAPTCHA Sample\\21.gif"); 175 | 176 | // Setup a rectangle to define your region of interest 177 | Rect roi(0, 0, img.cols, img.rows / 1.11); 178 | 179 | //Crop the full image to that image contained by the rectangle myROI 180 | Mat3b crop = img(roi); 181 | 182 | // Convert image to gray, blur and sharpen it 183 | Mat img_gray, img_sharp; 184 | cvtColor(crop, img_gray, CV_BGR2GRAY); 185 | blur(img_gray, img_gray, Size(4, 4)); 186 | 187 | GaussianBlur(img_gray, img_sharp, cv::Size(0, 0), 6); 188 | addWeighted(img_gray, 1.80, img_sharp, -0.60, 0, img_sharp); 189 | 190 | int histSize = 140; 191 | Mat histdata, img_sharp_not; 192 | bitwise_not(img_sharp, img_sharp_not); 193 | reduce(img_sharp_not, histdata, 0, CV_REDUCE_SUM, CV_32S); 194 | 195 | //Set the ranges ( for B,G,R) ) 196 | //float range[] = { 0, 256 }; 197 | //const float* histRange = { range }; 198 | //bool uniform = true; bool accumulate = false; 199 | //calcHist(&img_sharp, 1, 0, Mat(), histdata, 1, &histSize, &histRange, uniform, accumulate); 200 | 201 | //Calculate the histograms for input image 202 | int hist_w = img.cols * 4; int hist_h = img.rows * 4; 203 | int bin_w = cvRound((double)hist_w / histSize); 204 | 205 | int txtMargin = 20; 206 | Mat histImage(hist_h + txtMargin, hist_w + txtMargin, CV_8UC3, Scalar(255, 255, 255)); 207 | //Normalize the result to [ 0, histImage.rows ] 208 | normalize(histdata, histdata, 0, histImage.rows, NORM_MINMAX, -1, Mat()); 209 | 210 | //Draw histogram 211 | for (int i = 0; i < hist_h; i++) { 212 | if (i % 20 == 0) { 213 | ostringstream txt; 214 | txt << i; 215 | putText(histImage, txt.str(), Point(0, hist_h - i), 216 | 1, 0.75, Scalar::all(0), 1, 0); 217 | } 218 | } 219 | for (int i = 1; i < histSize; i++){ 220 | line(histImage, Point(bin_w*(i - 1) + txtMargin, hist_h - cvRound(histdata.at(i - 1))), 221 | Point(bin_w*(i) + txtMargin, hist_h - cvRound(histdata.at(i))), 222 | Scalar(255, 100, 0), 2, 8, 0); 223 | if (i % 10 == 0 || i == 1) { 224 | ostringstream txt; 225 | txt << i; 226 | putText(histImage, txt.str(), Point(bin_w*(i), hist_h + txtMargin), 227 | 1, 0.75, Scalar::all(0), 1, 0); 228 | } 229 | } 230 | 231 | Mat img_zeroone; 232 | threshold(img_sharp_not, img_zeroone, 20, 255, THRESH_BINARY); 233 | 234 | //Make good representation for clustering 235 | Mat points = Mat::zeros(sum(img_zeroone)[0], 2, CV_32F); 236 | for (int i = 0, k = 0; i < img_zeroone.rows; i++) { 237 | for (int j = 0; j < img_zeroone.cols; j++) { 238 | if ((int)img_zeroone.at(i, j) == 255) { 239 | points.at(k, 0) = i; 240 | points.at(k, 1) = j; 241 | k++; 242 | } 243 | } 244 | } 245 | Mat img_segmentation; 246 | img_sharp_not.copyTo(img_segmentation); 247 | //Clustering 248 | Mat kCenters, kLabels; 249 | int clusterCount = 5, attempts = 10, iterationNumber = 1e40; 250 | kmeans(points, clusterCount, kLabels, TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, iterationNumber, 1e-4), attempts, KMEANS_PP_CENTERS, kCenters); 251 | for (int i = 0; i < kCenters.rows; i++) { 252 | float x = kCenters.at(i, 1), y = kCenters.at(i, 0); 253 | circle(img_segmentation, Point(x, y), 2, (0, 0, 255), -1); 254 | rectangle(img_segmentation, Rect(x - 13, y - 13, 26, 26), Scalar(255, 255, 255)); 255 | } 256 | 257 | learnCNN(); 258 | 259 | // Show result 260 | imshow("Original", img); 261 | imshow("Crop", crop); 262 | imshow("Gray", img_gray); 263 | imshow("Sharpen", img_sharp); 264 | imshow("Sharpen not", img_sharp_not); 265 | imshow("Segmentation", img_segmentation); 266 | imshow("Zero One", img_zeroone); 267 | imshow("Histogram", histImage); 268 | 269 | waitKey(); 270 | 271 | return 0; 272 | } 273 | -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/byteswap.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint32_t byteswap_uint32(uint32_t a) 4 | { 5 | return ((((a >> 24) & 0xff) << 0) | 6 | (((a >> 16) & 0xff) << 8) | 7 | (((a >> 8) & 0xff) << 16) | 8 | (((a >> 0) & 0xff) << 24)); 9 | } -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/Break CAPTCHA/download.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # use this script for downloading Golestan CAPTCHA 3 | for ((i=0;i < 10000000;i++)){ 4 | wget -x --no-check-certificate https://support.nowpardaz.ir/frm/captcha/captcha.ashx -O ./$i.gif 5 | } 6 | exit 0 -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Diag1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Diag1.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/0.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/1.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/10.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/11.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/12.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/13.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/14.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/15.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/16.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/17.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/18.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/19.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/2.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/20.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/21.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/22.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/23.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/24.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/26.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/28.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/3.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/33.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/4.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/5.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/6.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/7.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/8.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CAPTCHA Sample/9.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CNN Network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/CNN Network.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/Golestan Page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/Golestan Page.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/Header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/Header.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/Image processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/Image processing.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/after k means.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/after k means.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/dataset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/dataset.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/google recaptcha.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/google recaptcha.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/hist1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/hist1.png -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/tweet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/assets/tweet.gif -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/blog post.txt: -------------------------------------------------------------------------------- 1 | [https://virgool.io/@hadiakhojasteh/how-to-break-a-golestan-captcha-system-with-machine-learning-kukzjnwwsqdx] 2 | 3 | چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟ 4 | 5 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/p35m1ui4lehq.png] 6 | 7 | همه‌ی ما از کپچا (CAPTCHA) فراری ایم - همون تصاویر مزاحمی رو میگم که نوشته های درهم ریخته است و برای اینکه به فرم یا صفحه ای از سایت دسترسی داشته باشیم باید اونو تایپ کنیم. کپچاها برای تشخیص انسان از بات ها (همون برنامه های اتوماتیک) و معمولا برای جلوگیری از ورود به بخشی خاص، جلوگیری از پر کردن فرم ها یا کاهش برخی حملات طراحی شدند. جالبه بدونید در حال حاضر مدتی است که کپچاهای متنی محبوبیت خودشون رو از دست دادند و جای خودشون رو به کپچاهای تصویری یا موارد مشابه دادند. 8 | 9 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/fs617g2e4pyt.gif] 10 | [نمونه ای از کپچای گوگل جایگزین مناسبی برای کپچاهای متنی] 11 | 12 | سیستم گلستان رو تقریبا همه می شناسند. سیستم اتوماسیون معروف دانشگاه های ایران که پیدا کردن هر چیزی داخل اون نیازمند یک دوره دکتری تخصصی "زبانهای رسمی و روش های صوری" است! 13 | توی این پست قصد داریم با رویکرد آموزشی و مرحله به مرحله، شکستن کپچای متنی سیستم گلستان رو با بهره گیری از قدرت یادگیری ماشین/عمیق و داده های آماری بررسی کنیم. توصیه میشه اگر دنبال دردسر نیستید این کار رو توی خونه امتحان نکنید😉. 14 | 15 | [...] 16 | 17 | برای شروع ماجراجویی، اول نگاهی به فرم ورود سیستم گلستان به همراه تصویر کپچای متنی می اندازیم: 18 | 19 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/rqpmt4fok2lo.png] 20 | [صفحه ورود سیستم گلستان] 21 | 22 | توی این صفحه یک تصویر جداگانه وجود داره که از طریق آدرس تصویر میشه بهش دسترسی داشت. بنابراین قدم اول ذخیره تعداد زیادی از این تصاویر هست تا با اون ها در مرحله بعد یک شبکه عصبی مصنوعی کانولوشنال (شبکه ای برای استخراج ویژگی ها از تصاویر و کلاس بندی) رو آموزش بدیم. نهایتا شبکه آموزش داده شده میتونه تصاویر ورودی رو به متن مورد نظر ترجمه کنه. 23 | 24 | *جمع آوری داده آموزشی* 25 | خُب، معمولا هر الگوریتم یادگیری ماشین برای آموزش نیازمند داده های زیادی هست. شکستن کپچا هم از این قاعده مستثنی نیست. بنابراین برای اینکه بتونیم یک کپچای متنی رو بشکنیم، نیازمند تعداد زیادی تصویر هستیم. برای اینکار یک اسکریپت ساده Shell میتونه چاره کار باشه. 26 | 27 | #! /bin/bash 28 | # use this script for downloading Golestan CAPTCHA 29 | for ((i=0;i < 10000000;i++)){ 30 | wget -x --no-check-certificate https://support.nowpardaz.ir/frm/captcha/captcha.ashx -O ./$i.gif 31 | } 32 | exit 0 33 | 34 | این اسکریپت سعی میکنه تعداد زیادی از فایل های تصویر رو دانلود کنه و با فرمت gif. ذخیره کنه (فرمت فایل های خروجی کدی هست که کپچا رو در سیستم اصلی تولید میکنه). 35 | 36 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/iaazfwsrnb20.png] 37 | [نمونه ای از تصاویر کپچاهای استخراج شده از سیستم گلستان] 38 | 39 | حالا حدالامکان تصاویر ورودی به سیستم رو به ساده ترین شکل ممکن تبدیل می کنیم. بدین منظور سعی میکنیم تا نوشته پایین تصاویر رو حذف کنیم. 40 | در این مطلب از کتابخونه OpenCV فریم ورک محبوب بینایی کامپیوتر و پردازش تصویر برای پیش پردازش تصاویر استفاده خواهیم کرد (اگر علاقمندید این کتابخونه Python API داره و می تونید از اون هم استفاده کنید). 41 | 42 | Mat3b img = imread(argv[1]); //Load image 43 | Rect roi(0, 0, img.cols, img.rows / 1.11); //Setup a rectangle to define region of interest 44 | Mat3b crop = img(roi); //Crop the full image to rectangle ROI 45 | imshow("Original", img); 46 | imshow("Crop", crop); 47 | 48 | کد بالا بخش پایین تصویر ورودی رو حذف میکنه که به عنوان یک آرگومان دریافت شده. بنابراین تا اینجای کار داده های آموزشی برای سیستم یادگیری مون رو در اختیار داریم. 49 | 50 | *پیش پردازش تصاویر* 51 | سیستم تشخیص کپچای ما می تونه مطابق شکل از شبکه عصبی مصنوعی برای پردازش تصاویر و برای شناسایی متن تصویر تشکیل شده باشه که یک تصویر از کپچای متنی رو به عنوان ورودی دریافت کرده و جواب صحیح رو تولید میکنه. 52 | 53 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/rpqadmjgarer.png] 54 | [رویکرد کلی سیستم یادگیری برای شکستن کپچا] 55 | 56 | با داشتن داده های آموزشی کافی، رویکرد کلی بالا پاسخ درستی تولید می کنه؛ یعنی فقط کافیه تعداد خیلی زیادی تصویر رو به یکی از لایه های شبکه عصبی کانولوشنال (Convolutional Neural Network) (احتمالا با یک معماری پیچیده و با تعداد لایه و پارامتر زیاد) که وظیفه پردازش تصویر رو داره بدیم و با یک لایه دیگه از شبکه عصبی که وظیفه پیش بینی در مورد کل تصویر رو داره مسئله رو حل کنیم. اما این رویکرد با کمی تغییرات پاسخ های بهتر با محاسبات کمتر رو تولید میکنه. پس سعی میکنیم به جای پیش بینی کل تصویر فقط یک حرف رو پیش بینی کنیم و تصویر رو به چند تصویر شامل حروف (یا اعداد) تبدیل کنیم. واضح هست که برای تعداد زیادی تصویر راه حل فتوشاپ توصیه نمیشه! 57 | خوشبختانه کپچایی که ما قصد شکستن اون رو داریم از پنج حرف تشکیل میشه. بنابراین اگر بتونیم روشی برای جداکردن حروف در تصویر داشته باشیم، شبکه عصبی تنها نیاز داره تا یک حرف رو کلاس بندی (Classify) کنه. یک روش ساده شکستن تصویر افقی به پنج قسمت مساوی هست. اما اگر به نمونه های دریافت شده در تصویر دقت کنید، ممکنه به دلیل جمع شدن حروف در یک طرف، حروف به درستی قطعه بندی (Segmentation) نشن. بنابراین برای اینکه محل دقیق تقسیم بندی در تصویر رو پیدا کنیم، سعی میکنیم تا تجمع پیکسل های غیر سفید در تصویر رو پیدا کنیم (یا به صورت ساده تعداد پیکسل در هر خط عمودی رو بشماریم)، و از اونجاییکه بین حروف فاصله کمی وجود داره، تعداد پیکسل بیشتر با تقریب خوبی جای هر حرف در تصویر رو به ما نشون میده. بعد از اینکار یک الگوریتم خوشه بندی (Clustering) می تونه به طور موثر تصویر رو به پنج بخش مختلف تقسیم کنه. 58 | ابتدا باید تصویر ورودی تبدیل به تصویر سیاه و سفید بشه و بخشی از نویز اون نیز حذف بشه تا مطمئن بشیم همه چیز به بهترین نحو ممکن انجام میشه. 59 | 60 | //Crop image and convert to gray, blur, sharpen, bitwise_not and black-white image 61 | Mat img_gray, img_sharp, img_sharp_not, img_zeroone; 62 | cvtColor(crop, img_gray, CV_BGR2GRAY); 63 | blur(img_gray, img_gray, Size(4, 4)); 64 | GaussianBlur(img_gray, img_sharp, cv::Size(0, 0), 6); 65 | addWeighted(img_gray, 1.80, img_sharp, -0.55, 0, img_sharp); 66 | bitwise_not(img_sharp, img_sharp_not); 67 | threshold(img_sharp_not, img_zeroone, 20, 255, THRESH_BINARY); 68 | 69 | کدهای بالا با پردازش تصویر، جادوی زیر رو انجام میده: 70 | 71 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/d548rahnyng1.png] 72 | [مراحل پردازش تصویر ورودی] 73 | 74 | برای قطعه بندی تصاویر؛ یعنی برش تصویر به کاراکترهای جداگانه، ساده ترین روش استفاده از نمودار هیستوگرام (Histogram) و یافتن دسته هایی از پیکسل هاست که در جای خاصی تجمع دارند. 75 | 76 | int histSize = 140; 77 | Mat histdata, img_sharp_not; 78 | bitwise_not(img_sharp, img_sharp_not); 79 | //Calculate the histograms for input image 80 | reduce(img_sharp_not, histdata, 0, CV_REDUCE_SUM, CV_32S); 81 | int hist_w = img.cols * 4; int hist_h = img.rows * 4; 82 | int bin_w = cvRound((double)hist_w / histSize); 83 | int txtMargin = 20; 84 | Mat histImage(hist_h + txtMargin, hist_w + txtMargin, CV_8UC3, Scalar(255, 255, 255)); 85 | //Normalize the result to [ 0, histImage.rows ] 86 | normalize(histdata, histdata, 0, histImage.rows, NORM_MINMAX, -1, Mat()); 87 | 88 | for (int i = 1; i < histSize; i++){ //Draw histogram in summary 89 | line(histImage, Point(bin_w*(i - 1) + txtMargin, hist_h - cvRound(histdata.at(i - 1))), Point(bin_w*(i) + txtMargin, hist_h - cvRound(histdata.at(i))), Scalar(255, 100, 0), 2, 8, 0); 90 | } 91 | 92 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/rhaivwdcikih.png] 93 | [نمودار هیستوگرام تعداد پیکسل ها برای قطعه بندی تصویر به ازای کپچای ورودی بالا سمت راست نمودار] 94 | 95 | همون طور که در تصویر هم می بینید نقاطی که افت شدید مقدار داره، دقیقا مکان های متناظری هستند که باید تصویر برش داده بشه تا تصاویر کاراکترها استخراج بشند. 96 | از اونجاییکه این روش با پیچیدگی هایی همراه هست، ما در اینجا با روش خوشه بندی k-means سعی میکنیم تا بهترین مکان برای جداسازی تصویر بعد از فیلتر رو پیدا کنیم. توی این روش از تصویر نهایی به شکل ماتریسی از صفر و یک ها (فقط نقاط سفید) که در مرحله قبل ایجاد کردیم، استفاده میکنیم. پنج نقطه اولیه تصادفی در ماتریس انتخاب میکنیم. با روش k-means سعی میکنیم نقاط درون تصویر رو به پنج خوشه (Cluster) تقسیم کنیم. نقطه مرکز هر خوشه، مرکز هر کاراکتر خواهد بود. 97 | 98 | //Make good representation for clustering 99 | Mat points = Mat::zeros(sum(img_zeroone)[0], 2, CV_32F); 100 | for (int i = 0, k = 0; i < img_zeroone.rows; i++) { 101 | for (int j = 0; j < img_zeroone.cols; j++) { 102 | if ((int)img_zeroone.at(i, j) == 255) { 103 | points.at(k, 0) = i; 104 | points.at(k, 1) = j; 105 | k++; 106 | } 107 | } 108 | } 109 | Mat kCenters, kLabels; //Clustering 110 | int clusterCount = 5, attempts = 10, iterationNumber = 1e40; 111 | kmeans(points, clusterCount, kLabels, TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, iterationNumber, 1e-4), attempts, KMEANS_PP_CENTERS, kCenters); 112 | for (int i = 0; i < kCenters.rows; i++) { 113 | float x = kCenters.at(i, 1), y = kCenters.at(i, 0); 114 | circle(img_sharp_not, Point(x, y), 2, (0, 0, 255), -1); 115 | rectangle(img_sharp_not, Rect(x - 13, y - 13, 26, 26), Scalar(255, 255, 255)); 116 | } 117 | نتیجه کدهای بالا باورنکردنیه: 118 | 119 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/fvrtzxnghqnh.png] 120 | [خروجی خوشه بندی پیکسل ها برای یافتن مرکز کاراکترها و قطعه بندی تصاویر] 121 | 122 | پردازش های بیشتری هم میشه روی تصویر انجام داد. مثلا برخی تصاویر که کنتراست (Contrast) کمتری دارند، قابلیت نرمال سازی و افزایش کنتراست رو دارند یا برای جداسازی از روش شمارش تجمعی، کاراکترهایی با طول های متفاوت رو جدا کرد. تا همین میزان پردازش برای ایجاد ورودی های شبکه عصبی؛ یعنی همون کاراکترهای جداگانه با اندازه ثابت، کافی است (اگر دوست دارید شما می تونید تا میزان دلخواه پردازش روی تصویر انجام بدید.). 123 | *ساخت و آموزش شبکه عصبی مصنوعی* 124 | از اونجاییکه ما فقط نیاز به تشخیص یک تصویر از حرف یا عدد داریم، نیازی به معماری پیچیده برای شبکه عصبی نداریم. شناسایی حروف یک مسئله بسیار ساده تر از تشخیص یک تصویر پیچیده (مثل تصاویری از سگ یا گربه که تنوع زیادی داره.) است. در اینجا ما برای حل مسئله شکستن کپچا از یک معماری شبکه عصبی مصنوعی با دو لایه کانولوشنال (Convolutional) همراه با Max Pooling و دو لایه تماما متصل (Fully-Connected) استفاده می کنیم. اگر شما این شبکه عصبی ها رو نمیشناسید نگران نباشید. در اینجا نیازی به پیاده سازی های سطح پایین نداریم. اگر علاقمند به یادگیری بیشتر در این زمینه هستید، ویکیپدیا یا این کتاب رو بررسی کنید. 125 | 126 | از اونجاییکه ما فقط نیاز به تشخیص یک تصویر از حرف یا عدد داریم، نیازی به معماری پیچیده برای شبکه عصبی نداریم. شناسایی حروف یک مسئله بسیار ساده تر از تشخیص یک تصویر پیچیده (مثل تصاویری از سگ یا گربه که تنوع زیادی داره.) است. در اینجا ما برای حل مسئله شکستن کپچا از یک معماری شبکه عصبی مصنوعی با دو لایه کانولوشنال (Convolutional) همراه با Max Pooling و دو لایه تماما متصل (Fully-Connected) استفاده می کنیم. اگر شما این شبکه عصبی ها رو نمیشناسید نگران نباشید. در اینجا نیازی به پیاده سازی های سطح پایین نداریم. اگر علاقمند به یادگیری بیشتر در این زمینه هستید، ویکیپد[https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/]یا یا این کتاب رو بر[https://en.wikipedia.org/wiki/Convolutional_neural_network]رسی کنید. 127 | 128 | [https://files.virgool.io/upload/users/7843/posts/kukzjnwwsqdx/sbpj28drsvta.png] 129 | [معماری شبکه عصبی مصنوعی کانولوشنال برای شکستن کپچا] 130 | 131 | برای سادگی آموزش در اینجا از TensorFlow؛ کتابخونه یادگیری ماشین گوگل، برای ایجاد شبکه استفاده خواهیم کرد. پیاده سازی این مدل به شکل زیر خواهد بود: 132 | 133 | #conv1 134 | with tf.variable_scope('conv1') as scope: 135 | kernel = _variable_with_weight_decay('weights', shape=[5, 5, 3, 64], stddev=5e-2, wd=None) 136 | conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME') 137 | biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0)) 138 | pre_activation = tf.nn.bias_add(conv, biases) 139 | conv1 = tf.nn.relu(pre_activation, name=scope.name) 140 | _activation_summary(conv1) 141 | #pool1 142 | pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool1') 143 | #norm1 144 | norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm1') 145 | #conv2 146 | with tf.variable_scope('conv2') as scope: 147 | kernel = _variable_with_weight_decay('weights', shape=[5, 5, 64, 64], stddev=5e-2, wd=None) 148 | conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding='SAME') 149 | biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.1)) 150 | pre_activation = tf.nn.bias_add(conv, biases) 151 | conv2 = tf.nn.relu(pre_activation, name=scope.name) 152 | _activation_summary(conv2) 153 | #norm2 154 | norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm2') 155 | #pool2 156 | pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool2') 157 | #FC3 158 | with tf.variable_scope('fc3') as scope: 159 | reshape = tf.reshape(pool2, [images.get_shape().as_list()[0], -1]) 160 | dim = reshape.get_shape()[1].value 161 | weights = _variable_with_weight_decay('weights', shape=[dim, 384], stddev=0.04, wd=0.004) 162 | biases = _variable_on_cpu('biases', [384], tf.constant_initializer(0.1)) 163 | fc3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name) 164 | _activation_summary(fc3) 165 | #FC4 166 | with tf.variable_scope(fc4') as scope: 167 | weights = _variable_with_weight_decay('weights', shape=[384,192], stddev=0.04, wd=0.004) 168 | biases = _variable_on_cpu('biases', [192], tf.constant_initializer(0.1)) 169 | fc4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name) 170 | _activation_summary(fc4) 171 | 172 | اگر بخش های دیگه کد رو هم به این مجموعه اضافه کنید و خوش شانس باشید خروجی زیر رو می بینید: 173 | 2018-04-25 11:45:45.927302: step 0, loss = 4.68 (2.0 examples/sec; 64.221 sec/batch) 174 | 2018-04-25 11:45:49.133065: step 10, loss = 4.66 (533.8 examples/sec; 0.240 sec/batch) 175 | 2018-04-25 11:45:51.397710: step 20, loss = 4.64 (597.4 examples/sec; 0.214 sec/batch) 176 | 2018-04-25 11:45:54.446850: step 30, loss = 4.62 (391.0 examples/sec; 0.327 sec/batch) 177 | ... 178 | 179 | داده های آموزشی برای این شبکه نیازمند برچسب هستند، برای اینکار می تونید مدل رو ابتدا با مجموعه تصاویر [https://www.nist.gov/itl/iad/image-group/emnist-dataset]EMNIST آموزش بدید و بعد با تصاویر اصلی استخراج شده آموزش رو انجام بدید. دقت این مدل رو میشه به ازای داده های ورودی اندازه گرفت، نمودارهای مختلف مثل دقت-سرعت رو در زمان اجرا با استفاده از داشبورد مربوطه رصد و بررسی کرد و کلی کار دیگه که می تونه دقت و سرعت مدل رو افزایش بده. با پیاده سازی مدل یادگیری عمیق، حالا ما می تونیم به صورت خودکار کپچای سیستم گلستان رو بشکنیم! 180 | این مطلب به صورت کامل در گیت هاب در دسترس هست. همچنین اگر علاقمند به موضوعات هوش مصنوعی، یادگیری ماشین و بینا[https://github.com/hkhojasteh]یی کامپیوتر هس[https://twitter.com/hadiakhojasteh]تید می تونید من رو در توییتر دنبال کنید. 181 | 182 | این ماجراجویی تموم شد. حالا نوبت شماست که دست به کار بشید، سیستم تشخیص کپچای دلخواهتون طراحی کنید و تجربیاتتون رو به اشتراک بذارید. به نظر شما راهکار جایگزین برای کپچاهای سنتی چه ویژگی هایی باید داشته باشه تا هوش مصنوعی نتونه اون رو بشکنه؟ 183 | 184 | آخرین تفریح سالمی که داشتم برای بازی 🕹 @takhfifan، @Digikalacom و @ShatelGroup با #هوش_مصنوعی و #پردازش_تصویر یک ماشین خودکار طراحی کردم. 😀 pic.twitter.com/LBdf7Fdc8r 185 | 186 | — Hadi Abdi Khojasteh (@hadiakhojasteh) June 16, 2017 187 | 188 | #بینایی کامپیوتر #هوش مصنوعی #یادگیری ماشین #شکستن کپچا #سیستم گلستان -------------------------------------------------------------------------------- /how-to-break-a-Golestan-CAPTCHA-system-with-machine-learning/چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟---kukzjnwwsqdx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟ 5 | 6 | 60 | 61 | 62 |
63 |
64 |

چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟

65 |
66 |
67 |

همه‌ی ما از کپچا (CAPTCHA) فراری ایم - همون تصاویر مزاحمی رو میگم که نوشته های درهم ریخته است و برای اینکه به فرم یا صفحه ای از سایت دسترسی داشته باشیم باید اونو تایپ کنیم. کپچاها برای تشخیص انسان از بات ها (همون برنامه های اتوماتیک) و معمولا برای جلوگیری از ورود به بخشی خاص، جلوگیری از پر کردن فرم ها یا کاهش برخی حملات طراحی شدند. جالبه بدونید در حال حاضر مدتی است که کپچاهای متنی محبوبیت خودشون رو از دست دادند و جای خودشون رو به کپچاهای تصویری یا موارد مشابه دادند.

نمونه ای از کپچای گوگل جایگزین مناسبی برای کپچاهای متنی
نمونه ای از کپچای گوگل جایگزین مناسبی برای کپچاهای متنی

سیستم گلستان رو تقریبا همه می شناسند. سیستم اتوماسیون معروف دانشگاه های ایران که پیدا کردن هر چیزی داخل اون نیازمند یک دوره دکتری تخصصی "زبانهای رسمی و روش های صوری" است!
توی این پست قصد داریم با رویکرد آموزشی و مرحله به مرحله، شکستن کپچای متنی سیستم گلستان رو با بهره گیری از قدرت یادگیری ماشین/عمیق و داده های آماری بررسی کنیم. توصیه میشه اگر دنبال دردسر نیستید این کار رو توی خونه امتحان نکنید😉.


برای شروع ماجراجویی، اول نگاهی به فرم ورود سیستم گلستان به همراه تصویر کپچای متنی می اندازیم:

صفحه ورود سیستم گلستان
صفحه ورود سیستم گلستان

توی این صفحه یک تصویر جداگانه وجود داره که از طریق آدرس تصویر میشه بهش دسترسی داشت. بنابراین قدم اول ذخیره تعداد زیادی از این تصاویر هست تا با اون ها در مرحله بعد یک شبکه عصبی مصنوعی کانولوشنال (شبکه ای برای استخراج ویژگی ها از تصاویر و کلاس بندی) رو آموزش بدیم. نهایتا شبکه آموزش داده شده میتونه تصاویر ورودی رو به متن مورد نظر ترجمه کنه.

جمع آوری داده آموزشی

خُب، معمولا هر الگوریتم یادگیری ماشین برای آموزش نیازمند داده های زیادی هست. شکستن کپچا هم از این قاعده مستثنی نیست. بنابراین برای اینکه بتونیم یک کپچای متنی رو بشکنیم، نیازمند تعداد زیادی تصویر هستیم. برای اینکار یک اسکریپت ساده Shell میتونه چاره کار باشه.

#! /bin/bash
 68 | # use this script for downloading Golestan CAPTCHA
 69 | for ((i=0;i < 10000000;i++)){
 70 |     wget -x --no-check-certificate https://support.nowpardaz.ir/frm/captcha/captcha.ashx -O ./$i.gif
 71 | }
 72 | exit 0

این اسکریپت سعی میکنه تعداد زیادی از فایل های تصویر رو دانلود کنه و با فرمت gif. ذخیره کنه (فرمت فایل های خروجی کدی هست که کپچا رو در سیستم اصلی تولید میکنه).

نمونه ای از تصاویر کپچاهای استخراج شده از سیستم گلستان
نمونه ای از تصاویر کپچاهای استخراج شده از سیستم گلستان

حالا حدالامکان تصاویر ورودی به سیستم رو به ساده ترین شکل ممکن تبدیل می کنیم. بدین منظور سعی میکنیم تا نوشته پایین تصاویر رو حذف کنیم.
در این مطلب از کتابخونه OpenCV فریم ورک محبوب بینایی کامپیوتر و پردازش تصویر و زبان ++C برای پیش پردازش تصاویر استفاده خواهیم کرد (اگر علاقمندید این کتابخونه Python API داره و می تونید از اون هم استفاده کنید).

    Mat3b img = imread(argv[1]);    //Load image
 73 |     Rect roi(0, 0, img.cols, img.rows / 1.11);    //Setup a rectangle to define region of interest
 74 |     Mat3b crop = img(roi);    //Crop the full image to rectangle ROI
 75 |     imshow("Original", img);
 76 |     imshow("Crop", crop);

کد بالا بخش پایین تصویر ورودی رو حذف میکنه که به عنوان یک آرگومان دریافت شده. بنابراین تا اینجای کار داده های آموزشی برای سیستم یادگیری مون رو در اختیار داریم.

پیش پردازش تصاویر

سیستم تشخیص کپچای ما می تونه مطابق شکل از شبکه عصبی مصنوعی برای پردازش تصاویر و برای شناسایی متن تصویر تشکیل شده باشه که یک تصویر از کپچای متنی رو به عنوان ورودی دریافت کرده و جواب صحیح رو تولید میکنه.

رویکرد کلی سیستم یادگیری برای شکستن کپچا
رویکرد کلی سیستم یادگیری برای شکستن کپچا

با داشتن داده های آموزشی کافی، رویکرد کلی بالا پاسخ درستی تولید می کنه؛ یعنی فقط کافیه تعداد خیلی زیادی تصویر رو به یکی از لایه های شبکه عصبی کانولوشنال (Convolutional Neural Network) (احتمالا با یک معماری پیچیده و با تعداد لایه و پارامتر زیاد) که وظیفه پردازش تصویر رو داره بدیم و با یک لایه دیگه از شبکه عصبی که وظیفه پیش بینی در مورد کل تصویر رو داره مسئله رو حل کنیم. اما این رویکرد با کمی تغییرات پاسخ های بهتر با محاسبات کمتر رو تولید میکنه. پس سعی میکنیم به جای پیش بینی کل تصویر فقط یک حرف رو پیش بینی کنیم و تصویر رو به چند تصویر شامل حروف (یا اعداد) تبدیل کنیم. واضح هست که برای تعداد زیادی تصویر راه حل فتوشاپ توصیه نمیشه!

خوشبختانه کپچایی که ما قصد شکستن اون رو داریم از پنج حرف تشکیل میشه. بنابراین اگر بتونیم روشی برای جداکردن حروف در تصویر داشته باشیم، شبکه عصبی تنها نیاز داره تا یک حرف رو کلاس بندی (Classify) کنه. یک روش ساده شکستن تصویر افقی به پنج قسمت مساوی هست. اما اگر به نمونه های دریافت شده در تصویر دقت کنید، ممکنه به دلیل جمع شدن حروف در یک طرف، حروف به درستی قطعه بندی (Segmentation) نشن. بنابراین برای اینکه محل دقیق تقسیم بندی در تصویر رو پیدا کنیم، سعی میکنیم تا تجمع پیکسل های غیر سفید در تصویر رو پیدا کنیم (یا به صورت ساده تعداد پیکسل در هر خط عمودی رو بشماریم)، و از اونجاییکه بین حروف فاصله کمی وجود داره، تعداد پیکسل بیشتر با تقریب خوبی جای هر حرف در تصویر رو به ما نشون میده. بعد از اینکار یک الگوریتم خوشه بندی (Clustering) می تونه به طور موثر تصویر رو به پنج بخش مختلف تقسیم کنه.

ابتدا باید تصویر ورودی تبدیل به تصویر سیاه و سفید بشه و بخشی از نویز اون نیز حذف بشه تا مطمئن بشیم همه چیز به بهترین نحو ممکن انجام میشه.

    //Crop image and convert to gray, blur, sharpen, bitwise_not and black-white image
 77 |     Mat img_gray, img_sharp, img_sharp_not, img_zeroone;
 78 |     cvtColor(crop, img_gray, CV_BGR2GRAY);
 79 |     blur(img_gray, img_gray, Size(4, 4));
 80 |     GaussianBlur(img_gray, img_sharp, cv::Size(0, 0), 6);
 81 |     addWeighted(img_gray, 1.80, img_sharp, -0.55, 0, img_sharp);
 82 |     bitwise_not(img_sharp, img_sharp_not);
 83 |     threshold(img_sharp_not, img_zeroone, 20, 255, THRESH_BINARY);

کدهای بالا با پردازش تصویر، جادوی زیر رو انجام میده:

مراحل پردازش تصویر ورودی
مراحل پردازش تصویر ورودی

برای قطعه بندی تصاویر؛ یعنی برش تصویر به کاراکترهای جداگانه، ساده ترین روش استفاده از نمودار هیستوگرام (Histogram) و یافتن دسته هایی از پیکسل هاست که در جای خاصی تجمع دارند.

    int histSize = 140;
 84 |     Mat histdata, img_sharp_not;
 85 |     bitwise_not(img_sharp, img_sharp_not);
 86 |     //Calculate the histograms for input image
 87 |     reduce(img_sharp_not, histdata, 0, CV_REDUCE_SUM, CV_32S);
 88 |     int hist_w = img.cols * 4; int hist_h = img.rows * 4;
 89 |     int bin_w = cvRound((double)hist_w / histSize);
 90 |     int txtMargin = 20;
 91 |     Mat histImage(hist_h + txtMargin, hist_w + txtMargin, CV_8UC3, Scalar(255, 255, 255));
 92 |     //Normalize the result to [ 0, histImage.rows ]
 93 |     normalize(histdata, histdata, 0, histImage.rows, NORM_MINMAX, -1, Mat());
 94 |     
 95 |     for (int i = 1; i < histSize; i++){    //Draw histogram in summary
 96 |         line(histImage, Point(bin_w*(i - 1) + txtMargin, hist_h - cvRound(histdata.at<int>(i - 1))), Point(bin_w*(i) + txtMargin, hist_h - cvRound(histdata.at<int>(i))), Scalar(255, 100, 0), 2, 8, 0);
 97 |      }
نمودار هیستوگرام تعداد پیکسل ها برای قطعه بندی تصویر به ازای کپچای ورودی بالا سمت راست نمودار
نمودار هیستوگرام تعداد پیکسل ها برای قطعه بندی تصویر به ازای کپچای ورودی بالا سمت راست نمودار

همون طور که در تصویر هم می بینید نقاطی که افت شدید مقدار داره، دقیقا مکان های متناظری هستند که باید تصویر برش داده بشه تا تصاویر کاراکترها استخراج بشند.

از اونجاییکه این روش با پیچیدگی هایی همراه هست، ما در اینجا با روش خوشه بندی k-means سعی میکنیم تا بهترین مکان برای جداسازی تصویر بعد از فیلتر رو پیدا کنیم. توی این روش از تصویر نهایی به شکل ماتریسی از صفر و یک ها (فقط نقاط سفید) که در مرحله قبل ایجاد کردیم، استفاده میکنیم. پنج نقطه اولیه تصادفی در ماتریس انتخاب میکنیم. با روش k-means سعی میکنیم نقاط درون تصویر رو به پنج خوشه (Cluster) تقسیم کنیم. نقطه مرکز هر خوشه، مرکز هر کاراکتر خواهد بود.

    //Make good representation for clustering
 98 |     Mat points = Mat::zeros(sum(img_zeroone)[0], 2, CV_32F);
 99 |     for (int i = 0, k = 0; i < img_zeroone.rows; i++) {
100 |         for (int j = 0; j < img_zeroone.cols; j++) {
101 |             if ((int)img_zeroone.at<char>(i, j) == 255) {
102 |                 points.at<float>(k, 0) = i;
103 |                 points.at<float>(k, 1) = j;
104 |                 k++;
105 |             }
106 |         }
107 |     }
108 |     Mat kCenters, kLabels;    //Clustering
109 |     int clusterCount = 5, attempts = 10, iterationNumber = 1e40;
110 |     kmeans(points, clusterCount, kLabels, TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, iterationNumber, 1e-4), attempts, KMEANS_PP_CENTERS, kCenters);
111 |     for (int i = 0; i < kCenters.rows; i++) {
112 |         float x = kCenters.at<float>(i, 1), y = kCenters.at<float>(i, 0);
113 |         circle(img_sharp_not, Point(x, y), 2, (0, 0, 255), -1);
114 |         rectangle(img_sharp_not, Rect(x - 13, y - 13, 26, 26), Scalar(255, 255, 255));
115 |     }

نتیجه کدهای بالا باورنکردنیه:

خروجی خوشه بندی پیکسل ها برای یافتن مرکز کاراکترها و قطعه بندی تصاویر
خروجی خوشه بندی پیکسل ها برای یافتن مرکز کاراکترها و قطعه بندی تصاویر

پردازش های بیشتری هم میشه روی تصویر انجام داد. مثلا برخی تصاویر که کنتراست (Contrast) کمتری دارند، قابلیت نرمال سازی و افزایش کنتراست رو دارند یا برای جداسازی از روش شمارش تجمعی، کاراکترهایی با طول های متفاوت رو جدا کرد. تا همین میزان پردازش برای ایجاد ورودی های شبکه عصبی؛ یعنی همون کاراکترهای جداگانه با اندازه ثابت، کافی است (اگر دوست دارید شما می تونید تا میزان دلخواه پردازش روی تصویر انجام بدید.).

ساخت و آموزش شبکه عصبی مصنوعی

از اونجاییکه ما فقط نیاز به تشخیص یک تصویر از حرف یا عدد داریم، نیازی به معماری پیچیده برای شبکه عصبی نداریم. شناسایی حروف یک مسئله بسیار ساده تر از تشخیص یک تصویر پیچیده (مثل تصاویری از سگ یا گربه که تنوع زیادی داره.) است. در اینجا ما برای حل مسئله شکستن کپچا از یک معماری شبکه عصبی مصنوعی با دو لایه کانولوشنال (Convolutional) همراه با Max Pooling و دو لایه تماما متصل (Fully-Connected) استفاده می کنیم. اگر شما این شبکه عصبی ها رو نمیشناسید نگران نباشید. در اینجا نیازی به پیاده سازی های سطح پایین نداریم. اگر علاقمند به یادگیری بیشتر در این زمینه هستید، ویکیپدیا یا این کتاب رو بررسی کنید.

معماری شبکه عصبی مصنوعی کانولوشنال برای شکستن کپچا
معماری شبکه عصبی مصنوعی کانولوشنال برای شکستن کپچا

برای سادگی آموزش در اینجا از TensorFlow؛ کتابخونه یادگیری ماشین گوگل، برای ایجاد شبکه استفاده خواهیم کرد. پیاده سازی این مدل به شکل زیر خواهد بود:

#conv1
116 | with tf.variable_scope('conv1') as scope:
117 |     kernel = _variable_with_weight_decay('weights', shape=[5, 5, 3, 64], stddev=5e-2, wd=None)
118 |     conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')
119 |     biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
120 |     pre_activation = tf.nn.bias_add(conv, biases)
121 |     conv1 = tf.nn.relu(pre_activation, name=scope.name)
122 |     _activation_summary(conv1)
123 | #pool1
124 | pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool1')
125 | #norm1
126 | norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm1')
127 | #conv2
128 | with tf.variable_scope('conv2') as scope:
129 |     kernel = _variable_with_weight_decay('weights', shape=[5, 5, 64, 64], stddev=5e-2, wd=None)
130 |     conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding='SAME')
131 |     biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.1))
132 |     pre_activation = tf.nn.bias_add(conv, biases)
133 |     conv2 = tf.nn.relu(pre_activation, name=scope.name)
134 |     _activation_summary(conv2)
135 | #norm2
136 | norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm2')
137 | #pool2
138 | pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool2')
139 | #FC3
140 | with tf.variable_scope('fc3') as scope:
141 |     reshape = tf.reshape(pool2, [images.get_shape().as_list()[0], -1])
142 |     dim = reshape.get_shape()[1].value
143 |     weights = _variable_with_weight_decay('weights', shape=[dim, 384], stddev=0.04, wd=0.004)
144 |     biases = _variable_on_cpu('biases', [384], tf.constant_initializer(0.1))
145 |     fc3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)
146 |      _activation_summary(fc3)
147 | #FC4
148 | with tf.variable_scope(fc4') as scope:
149 |     weights = _variable_with_weight_decay('weights', shape=[384,192], stddev=0.04, wd=0.004)
150 |     biases = _variable_on_cpu('biases', [192], tf.constant_initializer(0.1))
151 |     fc4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name)
152 |     _activation_summary(fc4)

اگر بخش های دیگه کد رو هم به این مجموعه اضافه کنید و خوش شانس باشید خروجی زیر رو می بینید:

2018-04-25 11:45:45.927302: step 0, loss = 4.68 (2.0 examples/sec; 64.221 sec/batch)
153 | 2018-04-25 11:45:49.133065: step 10, loss = 4.66 (533.8 examples/sec; 0.240 sec/batch)
154 | 2018-04-25 11:45:51.397710: step 20, loss = 4.64 (597.4 examples/sec; 0.214 sec/batch)
155 | 2018-04-25 11:45:54.446850: step 30, loss = 4.62 (391.0 examples/sec; 0.327 sec/batch)
156 | ...

داده های آموزشی برای این شبکه نیازمند برچسب هستند، برای اینکار می تونید مدل رو ابتدا با مجموعه تصاویر EMNIST آموزش بدید و بعد با تصاویر اصلی استخراج شده آموزش رو انجام بدید. دقت این مدل رو میشه به ازای داده های ورودی اندازه گرفت، نمودارهای مختلف مثل دقت-سرعت رو در زمان اجرا با استفاده از داشبورد مربوطه رصد و بررسی کرد و کلی کار دیگه که می تونه دقت و سرعت مدل رو افزایش بده. با پیاده سازی مدل یادگیری عمیق، حالا ما می تونیم به صورت خودکار کپچای سیستم گلستان رو بشکنیم!


این مطلب به صورت کامل در گیت هاب در دسترس هست. همچنین اگر علاقمند به موضوعات هوش مصنوعی، یادگیری ماشین و بینایی کامپیوتر هستید می تونید من رو در توییتر دنبال کنید.

ماشین خودکار هوشمند برای بازی کمپین دیجیکالا، تخفیفان و شاتل از توییتر
ماشین خودکار هوشمند برای بازی کمپین دیجیکالا، تخفیفان و شاتل از توییتر

این ماجراجویی تموم شد. حالا نوبت شماست که دست به کار بشید، سیستم تشخیص کپچای دلخواهتون رو طراحی کنید و تجربیاتتون رو به اشتراک بذارید. به نظر شما راهکار جایگزین برای کپچاهای سنتی چه ویژگی هایی باید داشته باشه تا هوش مصنوعی نتونه اون رو بشکنه؟

157 |
158 | 159 | 171 |
172 | 173 | -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/Intelligent Car/Intelligent Car.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | using namespace cv; 12 | using namespace std; 13 | 14 | Mat3b img, img_crop; 15 | Mat detected_edges, img_mask, img_line; 16 | 17 | bool less_left(const Vec4i& lhs, const Vec4i& rhs){ 18 | return lhs[0] < rhs[0]; 19 | } 20 | bool less_right(const Vec4i& lhs, const Vec4i& rhs) { 21 | return lhs[0] < rhs[0]; 22 | } 23 | 24 | // Standard Hough Line Transform 25 | void HoughTransform(void*) { 26 | Mat img_hlines = img_crop.clone(); 27 | // will hold the results of the detection 28 | vector lines, rightls, leftls; 29 | // runs the actual detection 30 | HoughLinesP(detected_edges, lines, 1, CV_PI / 180, 50, 30, 10); 31 | // Draw the lines 32 | for (size_t i = 0; i < lines.size(); i++) { 33 | Vec4f l = lines[i]; 34 | line(img_hlines, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 255), 2, CV_AA); 35 | 36 | //Calculating the slope and group lines 37 | float slope = (float)(l[3] - l[1]) / (l[2] - l[0]); 38 | if (slope > 0.40) { 39 | //printf("right %f\n", slope); 40 | rightls.push_back(l); 41 | }else if (slope < -0.40) { 42 | //printf("left %f\n", slope); 43 | leftls.push_back(l); 44 | } 45 | } 46 | // Find regions 47 | Point left_b, left_t, right_b, right_t; 48 | if (leftls.size() > 0) { 49 | auto lmmx = minmax_element(leftls.begin(), leftls.end(), less_left); 50 | left_b = Point(get<0>(lmmx)[0][0], get<0>(lmmx)[0][1]); 51 | left_t = Point(get<0>(lmmx)[0][2], get<0>(lmmx)[0][3]); 52 | }else{ 53 | // Set default values 54 | left_b = Point(img_hlines.cols / 2, img_hlines.rows - 20); 55 | left_t = Point(img_hlines.cols / 2, 75); 56 | } 57 | if (rightls.size() > 0) { 58 | auto rmmx = minmax_element(rightls.begin(), rightls.end(), less_right); 59 | right_t = Point(get<0>(rmmx)[0][0], get<0>(rmmx)[0][1]); 60 | right_b = Point(get<0>(rmmx)[0][2], get<0>(rmmx)[0][3]); 61 | }else{ 62 | // Set default values 63 | right_b = Point(img_hlines.cols / 2, img_hlines.rows - 20); 64 | right_t = Point(img_hlines.cols / 2, 75); 65 | } 66 | 67 | /*vector fitPoints; 68 | fitPoints.push_back(right_b); 69 | fitPoints.push_back(right_t); 70 | Vec4f l(0.0 ,0.0 ,0.0 ,0.0); 71 | fitLine(fitPoints, l, CV_DIST_L2, 0, 0.01, 0.01); 72 | line(img_hlines, Point(l[2] - m*l[0], l[2] - m*l[1]), Point(l[2] + m*l[0], l[2] + m*l[1]), (0, 255, 0));*/ 73 | 74 | Mat poly = img_hlines.clone(); 75 | vector vertices{ left_b, left_t, right_t, right_b }; 76 | vector> pts{ vertices }; 77 | fillPoly(poly, pts, Scalar(58, 190, 37, 0)); 78 | addWeighted(poly, 0.50, img_hlines, 0.50, 0, img_hlines); 79 | 80 | // Find reference line points by average top and bottom middle 81 | float rx = (((right_b.x - left_b.x) / 2 + left_b.x) + ((right_t.x - left_t.x) / 2 + left_t.x)) / 2; 82 | float ry = img_hlines.rows; 83 | // Draw dashed reference line 84 | Point p1(rx, 0); 85 | Point p2(rx, ry); 86 | LineIterator itl1(img_hlines, p1, p2, 8); // get a line iterator 87 | LineIterator itl2(img_hlines, Point(p1.x + 1, p1.y), Point(p2.x + 1, p2.y), 8); // get a line iterator 88 | for (int i = 0; i < itl1.count; i++, itl1++, itl2++) { 89 | if (i % 5 != 0) { 90 | // every 5'th pixel gets dropped, blue stipple line 91 | (*itl1)[1] = (*itl2)[1] = 80; 92 | (*itl1)[2] = (*itl2)[2] = 75; 93 | } 94 | } 95 | vector trivertices{ Point(rx - 7, ry - 1), Point(rx + 7, ry - 1), Point(rx, ry - 8) }; 96 | vector> tripts{ trivertices }; 97 | fillPoly(img_hlines, tripts, Scalar(103, 80, 75, 0)); 98 | 99 | img.copyTo(img_line); 100 | img_hlines.copyTo(img_line(Rect(0, 325, img_hlines.cols, img_hlines.rows))); 101 | 102 | imshow("detected lines", img_line); 103 | } 104 | 105 | int const max_lowThreshold = 255; 106 | int lowThreshold = 210, ratio = 3, kernel_size = 3; 107 | char* window_name = "Edge Map"; 108 | // CannyThreshold: Trackbar callback - Canny thresholds input with a ratio 1:3 109 | void CannyThreshold(int, void*){ 110 | // Reduce noise with a kernel 3x3 111 | blur(img_mask, detected_edges, Size(3, 3)); 112 | 113 | // Canny detector 114 | Canny(detected_edges, detected_edges, lowThreshold, lowThreshold * ratio, kernel_size); 115 | 116 | // Using Canny's output as a mask and display our result 117 | imshow(window_name, detected_edges); 118 | 119 | HoughTransform(0); 120 | } 121 | 122 | int main(int argc, char** argv){ 123 | // Load image 124 | //img = imread("..\\assets\\Road Sample\\Sample10.png"); 125 | 126 | //VideoCapture cap(0); // open the camera 127 | 128 | VideoCapture cap("..\\assets\\2.mp4"); 129 | // Check if camera opened successfully 130 | if (!cap.isOpened()) { 131 | cout << "Error opening video stream or file" << endl; 132 | return -1; 133 | } 134 | 135 | while (1) { 136 | // Capture frame-by-frame 137 | cap >> img; 138 | // If the frame is empty, break immediately 139 | if (img.empty()) { 140 | double count = cap.get(CV_CAP_PROP_FRAME_COUNT); //get the frame count 141 | cap.set(CV_CAP_PROP_POS_FRAMES, 0); //Set index to last frame 142 | continue; 143 | } 144 | // Display the resulting frame 145 | //imshow("Frame", img); 146 | // Press ESC on keyboard to exit 147 | char c = (char)waitKey(25); 148 | if (c == 27) 149 | break; 150 | 151 | // Setup a rectangle to define your region of interest 152 | Rect roi(0, 325, img.cols, img.rows - 455); //5 153 | //Rect roi(0, 420, img.cols, img.rows - 500); //1 , 10 154 | //Rect roi(0, 0, img.cols, img.rows); 155 | 156 | //Crop the full image to that image contained by the rectangle myROI 157 | img_crop = img(roi); 158 | 159 | // Convert image to gray, blur and sharpen it 160 | Mat img_gray, mask_hsv_yellow, mask_white; 161 | cvtColor(img_crop, img_gray, CV_BGR2GRAY); 162 | 163 | // Make target image by apply yellow and white mask 164 | Scalar m = mean(img_gray); 165 | cvtColor(img, mask_hsv_yellow, CV_BGR2HSV); 166 | inRange(img_crop, Scalar(20, 85, 85), Scalar(30, 255, 255), mask_hsv_yellow); 167 | inRange(img_gray, Scalar(m[0] + (255 - m[0]) / 3.5), Scalar(255), mask_white); 168 | bitwise_or(mask_white, mask_hsv_yellow, img_mask); 169 | // bitwise_or(img_gray, img_mask, img_mask); 170 | GaussianBlur(img_mask, img_mask, cv::Size(5, 5), 0); 171 | 172 | detected_edges.create(img_mask.size(), img_mask.type()); 173 | // Create a window 174 | namedWindow(window_name); 175 | // Create a Trackbar for user to enter threshold 176 | createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold); 177 | // Show the image 178 | CannyThreshold(0, 0); 179 | 180 | // Show result 181 | //imshow("Original", img); 182 | //imshow("Crop", crop); 183 | //imshow("Gray", img_gray); 184 | //imshow("Mask", img_mask); 185 | } 186 | // When everything done, release the video capture object 187 | cap.release(); 188 | 189 | waitKey(0); 190 | 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/Intelligent Car/cansniffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.IO.Ports; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | 13 | namespace CANReadWrite{ 14 | public partial class Form1 : Form{ 15 | public SerialPort serialPort; 16 | public Form1(){ 17 | InitializeComponent(); 18 | } 19 | 20 | private void ui_btn_read_Click(object sender, EventArgs e){ 21 | if (serialPort == null || !serialPort.IsOpen){ 22 | serialPort = new SerialPort("COM7"); 23 | serialPort.Open(); 24 | }else{ 25 | serialPort.Close(); 26 | } 27 | 28 | if (ui_btn_read.Text == "ReadPort"){ 29 | ui_btn_read.Text = "StopRead"; 30 | }else{ 31 | ui_btn_read.Text = "ReadPort"; 32 | } 33 | 34 | isRead = !isRead; 35 | readData(); 36 | } 37 | 38 | private bool isRead = false; 39 | private void readData(){ 40 | string fileName = DateTime.Now.ToString("HHmmss") + ".txt"; 41 | byte[] data = new byte[20]; 42 | while (true){ 43 | if (!isRead){ 44 | return; 45 | } 46 | int len = serialPort.BytesToRead; 47 | len = len > 20 ? 20 : len; 48 | serialPort.Read(data, 0, len); 49 | using (var stream = new FileStream(fileName, FileMode.Append)){ 50 | stream.Write(data, 0, data.Length); 51 | } 52 | StringBuilder hex = new StringBuilder(data.Length * 2); 53 | for (int i = 0; i < data.Length; i += 2){ 54 | hex.AppendFormat("{0:x2}{1:x2} ", data[i], data[i + 1]); 55 | } 56 | ui_rtb_dataRead.Text += hex.ToString(); 57 | Application.DoEvents(); 58 | } 59 | } 60 | 61 | List frames; 62 | List framesIds = new List(); 63 | private void updateFrameData(List data){ 64 | try { 65 | string idf = (BitConverter.ToUInt16(data.ToArray(), 0) & 0X7FF0).ToString("X2"); 66 | string ids = (BitConverter.ToUInt32(data.ToArray(), 1) & 0X03FFFF00).ToString("X2"); 67 | //string len = ((BitConverter.ToUInt16(data.ToArray(), 4) & 0X1E00) >> 9).ToString(); 68 | string len = ((BitConverter.ToUInt16(data.ToArray(), 1) & 0X01E0) >> 5).ToString(); 69 | 70 | StringBuilder formatdata = new StringBuilder(data.Count * 2); 71 | for (int i = 2; i < data.Count && i < 10; i += 2){ 72 | formatdata.AppendFormat("{0:x2}{1:x2} ", data[i], data[i + 1]); 73 | } 74 | if (!framesIds.Exists(s => s == idf + ids)){ 75 | frames.Add(idf + " " + ids + " " + len + " " + formatdata.ToString()); 76 | framesIds.Add(idf + ids); 77 | } 78 | }catch{ }; 79 | } 80 | 81 | private void ui_btn_readfile_Click(object sender, EventArgs e){ 82 | frames = new List(); 83 | int nof7Fs = 0; 84 | byte[] databyte = File.ReadAllBytes("210419.txt"); //220227.txt, 222809.txt, 211826.txt, 210419.txt 85 | List realdata = new List(); 86 | for (int i = 0, charCount = 0; i < databyte.Length; i++){ 87 | string byted = (databyte[i]).ToString("X2"); 88 | if (byted != "3F"){ 89 | realdata.Add(databyte[i]); 90 | if (byted == "7F"){ 91 | updateFrameData(realdata); 92 | nof7Fs++; 93 | realdata.Clear(); 94 | AppendText(this.ui_rtb_dataRead, byted, Color.Red, Color.Yellow); 95 | charCount++; 96 | //Update frames 97 | ui_lbl_info.Text = "7F: " + nof7Fs; 98 | ui_rtb_frames.Text = frames.Aggregate((k, j) => k + "\n" + j); 99 | }else{ 100 | AppendText(this.ui_rtb_dataRead, byted); 101 | charCount++; 102 | } 103 | } 104 | if (charCount % 2 == 0){ 105 | AppendText(this.ui_rtb_dataRead, " "); 106 | } 107 | if (charCount % 20 == 0){ 108 | // scroll it automatically 109 | ui_rtb_dataRead.SelectionStart = ui_rtb_dataRead.Text.Length; 110 | ui_rtb_dataRead.ScrollToCaret(); 111 | } 112 | } 113 | //ui_rtb_dataRead.Text += (BitConverter.ToInt16(databyte, i) | 0x7F).ToString("X"); 114 | } 115 | 116 | void AppendText(RichTextBox box, string text, Color? fcolor = null, Color? bcolor = null){ 117 | int start = box.TextLength; 118 | box.AppendText(text); 119 | int end = box.TextLength; 120 | 121 | // Textbox may transform chars, so (end-start) != text.Length 122 | box.Select(start, end - start);{ 123 | box.SelectionColor = fcolor.GetValueOrDefault(Color.LightGray); 124 | box.SelectionBackColor = bcolor.GetValueOrDefault(Color.Black); 125 | // could set box.SelectionBackColor, box.SelectionFont too. 126 | } 127 | box.SelectionLength = 0; // clear 128 | } 129 | 130 | private void ui_btn_readtxtfile_Click(object sender, EventArgs e){ 131 | frames = new List(); 132 | int nof7Fs = 0; 133 | string databyte = File.ReadAllText("p5.txt"); 134 | List realdata = new List(); 135 | for (int i = 0, charCount = 0; i < databyte.Length - 1; i += 2){ 136 | string byted = databyte[i].ToString() + databyte[i + 1].ToString(); 137 | if (byted != "3F"){ 138 | realdata.Add(Encoding.ASCII.GetBytes(byted)[0]); 139 | if (byted == "7f"){ 140 | updateFrameData(realdata); 141 | nof7Fs++; 142 | realdata.Clear(); 143 | AppendText(this.ui_rtb_dataRead, byted, Color.Red, Color.Yellow); 144 | charCount++; 145 | }else{ 146 | AppendText(this.ui_rtb_dataRead, byted); 147 | charCount++; 148 | } 149 | } 150 | if (charCount == 2){ 151 | AppendText(this.ui_rtb_dataRead, " "); 152 | charCount = 0; 153 | } 154 | } 155 | ui_lbl_info.Text = "7F: " + nof7Fs; 156 | ui_rtb_frames.Text = frames.Aggregate((i, j) => i + "\n" + j); 157 | } 158 | 159 | private void ui_btn_writeFromFile_Click(object sender, EventArgs e){ 160 | string databyte = File.ReadAllText("f_2180.txt"); //f_47A0, f_2180, f_5880 161 | List realdata = new List(); 162 | 163 | if (serialPort == null || !serialPort.IsOpen){ 164 | serialPort = new SerialPort("COM7"); 165 | serialPort.Open(); 166 | } 167 | for (int i = 0; i < databyte.Length - 1; i++){ 168 | string byted = databyte[i].ToString() + databyte[i + 1].ToString(); 169 | serialPort.Write(byted.ToLower()); 170 | } 171 | } 172 | 173 | private void ui_btn_demo_Click(object sender, EventArgs e){ 174 | frames = new List(); 175 | int nof7Fs = 0; 176 | string[] paths = { "220227.txt", "222809.txt", "211826.txt", "210419.txt", 177 | "220227.txt", "222809.txt", "211826.txt", "210419.txt", 178 | "220227.txt", "222809.txt", "211826.txt", "210419.txt", 179 | "220227.txt", "222809.txt", "211826.txt", "210419.txt", 180 | "220227.txt", "222809.txt", "211826.txt", "210419.txt"}; 181 | foreach (string path in paths){ 182 | byte[] databyte = File.ReadAllBytes(path); //220227.txt, 222809.txt, 211826.txt, 210419.txt 183 | List realdata = new List(); 184 | for (int i = 0, charCount = 0; i < databyte.Length; i++){ 185 | string byted = (databyte[i]).ToString("X2"); 186 | if (byted != "3F"){ 187 | realdata.Add(databyte[i]); 188 | if (byted == "7F"){ 189 | updateFrameData(realdata); 190 | nof7Fs++; 191 | realdata.Clear(); 192 | AppendText(this.ui_rtb_dataRead, byted, Color.Red, Color.Yellow); 193 | charCount++; 194 | //Update frames 195 | ui_lbl_info.Text = "7F: " + nof7Fs; 196 | try{ 197 | ui_rtb_frames.Text = frames.Aggregate((k, j) => k + "\n" + j); 198 | }catch{ } 199 | }else{ 200 | AppendText(this.ui_rtb_dataRead, byted); 201 | charCount++; 202 | } 203 | } 204 | if (charCount % 2 == 0){ 205 | AppendText(this.ui_rtb_dataRead, " "); 206 | } 207 | if (charCount % 100 == 0){ 208 | // scroll it automatically 209 | ui_rtb_dataRead.SelectionStart = ui_rtb_dataRead.Text.Length; 210 | ui_rtb_dataRead.ScrollToCaret(); 211 | Application.DoEvents(); 212 | } 213 | } 214 | } 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/Intelligent Car/client.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * OpenCV video streaming over TCP/IP 3 | * Client: Receives video from server and display it 4 | */ 5 | 6 | #include "opencv2/opencv.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace cv; 12 | 13 | int main(int argc, char** argv){ 14 | //-------------------------------------------------------- 15 | //networking stuff: socket , connect 16 | //-------------------------------------------------------- 17 | int sokt; 18 | char* serverIP; 19 | int serverPort; 20 | 21 | if (argc < 3) { 22 | std::cerr << "Usage: cv_video_cli " << std::endl; 23 | } 24 | 25 | serverIP = argv[1]; 26 | serverPort = atoi(argv[2]); 27 | 28 | struct sockaddr_in serverAddr; 29 | socklen_t addrLen = sizeof(struct sockaddr_in); 30 | 31 | if ((sokt = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 32 | std::cerr << "socket() failed" << std::endl; 33 | } 34 | 35 | serverAddr.sin_family = PF_INET; 36 | serverAddr.sin_addr.s_addr = inet_addr(serverIP); 37 | serverAddr.sin_port = htons(serverPort); 38 | 39 | if (connect(sokt, (sockaddr*)&serverAddr, addrLen) < 0) { 40 | std::cerr << "connect() failed!" << std::endl; 41 | } 42 | 43 | //---------------------------------------------------------- 44 | //OpenCV Code 45 | //---------------------------------------------------------- 46 | 47 | Mat img; 48 | img = Mat::zeros(480 , 640, CV_8UC1); 49 | int imgSize = img.total() * img.elemSize(); 50 | uchar *iptr = img.data; 51 | int bytes = 0; 52 | int key; 53 | 54 | //make img continuos 55 | if ( ! img.isContinuous() ) { 56 | img = img.clone(); 57 | } 58 | 59 | std::cout << "Image Size:" << imgSize << std::endl; 60 | 61 | namedWindow("CV Video Client",1); 62 | 63 | while (key != 'q') { 64 | if ((bytes = recv(sokt, iptr, imgSize , MSG_WAITALL)) == -1) { 65 | std::cerr << "recv failed, received bytes = " << bytes << std::endl; 66 | } 67 | cv::imshow("CV Video Client", img); 68 | if (key = cv::waitKey(10) >= 0) break; 69 | } 70 | 71 | close(sokt); 72 | return 0; 73 | } -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/Intelligent Car/serveur.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * OpenCV video streaming over TCP/IP 3 | * Server: Captures video from a webcam and send it to a client 4 | */ 5 | 6 | #include "opencv2/opencv.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace cv; 16 | 17 | void *display(void *); 18 | 19 | int capDev = 0; 20 | VideoCapture cap(capDev); // open the default camera 21 | 22 | int main(int argc, char** argv){ 23 | //-------------------------------------------------------- 24 | //networking stuff: socket, bind, listen 25 | //-------------------------------------------------------- 26 | int localSocket, 27 | remoteSocket, 28 | port = 4097; 29 | 30 | struct sockaddr_in localAddr, 31 | remoteAddr; 32 | pthread_t thread_id; 33 | 34 | int addrLen = sizeof(struct sockaddr_in); 35 | 36 | if ( (argc > 1) && (strcmp(argv[1],"-h") == 0) ) { 37 | std::cerr << "usage: ./cv_video_srv [port] [capture device]\n" << 38 | "port : socket port (4097 default)\n" << 39 | "capture device : (0 default)\n" << std::endl; 40 | exit(1); 41 | } 42 | 43 | if (argc == 2) port = atoi(argv[1]); 44 | 45 | localSocket = socket(AF_INET , SOCK_STREAM , 0); 46 | if (localSocket == -1){ 47 | perror("socket() call failed!!"); 48 | } 49 | 50 | localAddr.sin_family = AF_INET; 51 | localAddr.sin_addr.s_addr = INADDR_ANY; 52 | localAddr.sin_port = htons( port ); 53 | 54 | if( bind(localSocket,(struct sockaddr *)&localAddr , sizeof(localAddr)) < 0) { 55 | perror("Can't bind() socket"); 56 | exit(1); 57 | } 58 | 59 | //Listening 60 | listen(localSocket , 3); 61 | 62 | std::cout << "Waiting for connections...\n" 63 | << "Server Port:" << port << std::endl; 64 | 65 | //accept connection from an incoming client 66 | while(1){ 67 | //if (remoteSocket < 0) { 68 | // perror("accept failed!"); 69 | // exit(1); 70 | //} 71 | 72 | remoteSocket = accept(localSocket, (struct sockaddr *)&remoteAddr, (socklen_t*)&addrLen); 73 | //std::cout << remoteSocket<< "32"<< std::endl; 74 | if (remoteSocket < 0) { 75 | perror("accept failed!"); 76 | exit(1); 77 | } 78 | std::cout << "Connection accepted" << std::endl; 79 | pthread_create(&thread_id,NULL,display,&remoteSocket); 80 | 81 | //pthread_join(thread_id,NULL); 82 | 83 | } 84 | //pthread_join(thread_id,NULL); 85 | //close(remoteSocket); 86 | return 0; 87 | } 88 | 89 | void *display(void *ptr){ 90 | int socket = *(int *)ptr; 91 | //OpenCV Code 92 | //---------------------------------------------------------- 93 | 94 | Mat img, imgGray; 95 | img = Mat::zeros(480 , 640, CV_8UC1); 96 | //make it continuous 97 | if (!img.isContinuous()) { 98 | img = img.clone(); 99 | } 100 | 101 | int imgSize = img.total() * img.elemSize(); 102 | int bytes = 0; 103 | int key; 104 | 105 | //make img continuos 106 | if ( ! img.isContinuous() ) { 107 | img = img.clone(); 108 | imgGray = img.clone(); 109 | } 110 | 111 | std::cout << "Image Size:" << imgSize << std::endl; 112 | 113 | while(1) { 114 | /* get a frame from camera */ 115 | cap >> img; 116 | 117 | //do video processing here 118 | cvtColor(img, imgGray, CV_BGR2GRAY); 119 | 120 | //send processed image 121 | if ((bytes = send(socket, imgGray.data, imgSize, 0)) < 0){ 122 | std::cerr << "bytes = " << bytes << std::endl; 123 | break; 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/4.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/BCM Map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/BCM Map.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/BCM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/BCM.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Capture Video.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Capture Video.gif -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Header.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Hough Transform out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Hough Transform out.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Lamp Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Lamp Schematic.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Rana Nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Rana Nodes.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample1.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample10.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample2.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample3.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample3_ref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample3_ref.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample4.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample5.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample6.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample6_ref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample6_ref.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample7.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample8.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/Road Sample/Sample9.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/T Connector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/T Connector.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/alarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/alarm.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/can format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/can format.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/canny edge detector out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/canny edge detector out.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/cansniffer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/cansniffer.gif -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/car.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/convert to gray and crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/convert to gray and crop.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/edge sample in our images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/edge sample in our images.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/hough-mb_parameter_space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/hough-mb_parameter_space.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/inRange bitwise_or.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/inRange bitwise_or.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/line finding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/line finding.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/output sample for day and night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/output sample for day and night.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/reference line detection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/reference line detection.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/sendFrame.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/sendFrame.gif -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/solidWhiteRight.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/solidWhiteRight.mp4 -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/solidYellowLeft.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/solidYellowLeft.mp4 -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/twitter.png -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/assets/waymo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/assets/waymo.jpeg -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/blog post.txt: -------------------------------------------------------------------------------- 1 | [https://virgool.io/@hadiakhojasteh/how-to-build-an-intelligent-car-with-image-processing-rkgz4q8v37xg] 2 | 3 | هک خودرو؛ چطوری با پردازش تصویر خودرومونو هوشمند کنیم؟ 4 | 5 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/yx14h0mtzuie.png] 6 | 7 | در حال حاضر بیش از 20 میلیون خودرو در جاده های ایران وجود داره و این تعداد در جهان بیش از یک میلیارد هست. آماری که باعث میشه امنیت یکپارچه، بخشی جداناپذیر از وسایل نقلیه بسیاری از تولیدکنندگان خودرو باشه و بسیاری از قوانین و استانداردها برای امنیت وسایل نقلیه وجود داشته باشه. با این حال هک خودرو عمری به اندازه 15 سال داره؛ تغییر مدیریت موتور و تزریق سوخت، ارسال سیگنال های مخفی برای واحدهای کنترل الکترونیکی (Electronic Control Units یا ECUs) خودرو یا ارسال ترافیک جعلی برای سیستم مسیریابی آنلاین و تغییر مسیر خودرو در این سال ها اتفاق افتاده. جالبه بدونید به صورت غیر رسمی گروه هایی ادعای دسترسی غیرمجاز به سیستم ایمنی خودروها یا ارتباط از راه دور با خودروهای متصل رو داشتند. 8 | 9 | از طرف دیگه، در سال های اخیر هوش مصنوعی با ورود به دنیای وسایل نقلیه، نمونه های موفقی از خودروهای خودران هوشمند رو به دنیا معرفی کرده. با مستقر شدن تعداد کافی از این خودروهای خودران، جان میلیون ها انسان از خطر مرگ حفظ میشه و به شکل چشم گیری سرعت گذر جهان به انرژی های پاک بیشتر خواهد شد. 10 | 11 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/ezyues9ag6r1.jpeg] 12 | خودروی خودران شرکت Waymo (زیر مجموعه هلدینگ آلفابت) با بهره گیری از تجارب خودرو خودران گوگل 13 | 14 | در این پست قصد داریم با رویکرد آموزشی و مرحله به مرحله، سیستمی طراحی کنیم که پس از دریافت تصاویر دوربین تعبیه شده در جلوی خودرو و پردازش این تصاویر، تغییر مسیر ناگهانی راننده بر اثر خستگی یا خطای انسانی رو تشخیص داده و از طریق علائم جلو داشبورد داخل خودرو به راننده اخطار بده. 15 | برای پیاده سازی این سیستم، از یک طرف تصاویر دوربین رو به لپ تاپ ارسال کرده و از طرف دیگه فرمان های کنترلی برای هشدار به راننده رو به سامانه مالتی پلکس خودرو ارسال میکنیم؛ یعنی تصاویر به صورت بلادرنگ (Real-time) پردازش شده و در صورت تغییر مسیر ناگهانی، فرمان هشدار به راننده داده میشه. از اونجاییکه برای ایجاد این سیستم و دسترسی به سیستم شبکه خودرو نیازمند کمی قهرمان بازی هستیم، توصیه میشه اگر دنبال دردسر نیستید این کار رو روی خودرو خودتون امتحان نکنید😉. 16 | 17 | در این ماجراجویی، خودرو "رانا" رو انتخاب کردیم. خودرویی که بر پایه پلتفرم 206 صندوق دار و با کمی تغییر در ظاهر و چراغ های جلو و عقب ساخته شده. البته با نگاهی فنی تر به این خودرو، متوجه میشید که از تمامی تولیدات خودروساز، وسیله و قطعه ای در این خودرو وجود داره. 18 | 19 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/hrquqykmga3a.png] 20 | خودروی مورد آزمایش؛ هدف ایجاد یک سیستم هشدار برای مواقعی هست که خودرو از مسیر اصلی یا از باند جاده ای که در حال حرکت هست خارج میشه. 21 | 22 | در بخش اول سعی میکنیم تصاویر گرفته شده از جلوی خودرو رو پردازش کرده و مسیر حرکت اصلی خودرو رو تشخیص بدیم و در بخش دوم با هک خودرو و متصل شدن به شبکه الکترونیکی داخل خودرو، فرمان های کنترلی لازم برای هشدار به راننده رو ارسال میکنیم. 23 | 24 | پردازش تصاویر دریافتی 25 | زمانیکه ما رانندگی می کنیم، با کمک چشمامون خطوط جاده رو به عنوان یک مرجع ثابت برای تصمیم گیری ها و هدایت خودرو در نظر می گیریم. این اولین چیزیه که در طراحی خودروهای خودران توسط الگوریتم های مختلف پیاده سازی می شه. در اینجا ما تصویری مشابه تصویر سمت راست رو دریافت کرده و با الگوریتم های پردازش تصویر، مسیر (لاین) ی که در حال حرکت در اون هستیم - مشابه تصویر سمت چپ - رو مشخص میکنیم. در این پست از ویدیو هایی که در هنگام رانندگی از جاده ها در روز و شب از داخل ماشین ضبط کردیم، استفاده میکنیم. این تصاویر به علت سرعت بالای خودرو، مناسب نبودن مکان دوربین و نور و محیط واقعی دارای نویز بسیار بالایی هستند. 26 | 27 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/w0057og9gis0.png] 28 | نمونه خروجی سیستم برای تصاویر واقعی گرفته شده از رانندگی که در آنها نور محیطی و نویز مشهود است؛ سمت راست تصاویر ورودی و سمت چپ تصاویر پردازش شده برای تشخیص لاین فعلی در حال رانندگی برای روز (بالا) و شب (پایین) 29 | 30 | طیف خاکستری و حذف نویز 31 | در این پست برای پردازش تصاویر از OpenCV فریم ورک بینایی کامپیوتر - پردازش تصویر و زبان ++C استفاده خواهیم کرد. در اولین گام بخش بالا و پایین تصاویر که اطلاعات مهمی از جاده رو شامل نمیشند، حذف میکنیم. چون بیشتر الگوریتم ها از تفاوت تغییر رنگ (یا همان نور یا تاثیر گذاری یک شی در بخشی از تصویر و در اینجا خط کشی جاده) استفاده می کنند، در همین مرحله تصویر رو به طیف خاکستری تبدیل می کنیم؛ یعنی مقدار هر پیکسل در سه کانال رنگی تصویر (قرمز، سبز و آبی یا RGB) ورودی رو به یک مقدار بین 0 تا 255 تبدیل میکنیم. 32 | 33 | Mat3b img = imread(argv[1]); //Load image 34 | Rect roi(0, 420, img.cols, img.rows - 500); //Setup a rectangle to define region of interest 35 | Mat3b img_crop = img(roi); //Crop the full image to rectangle ROI 36 | Mat img_gray; 37 | cvtColor(img_crop, img_gray, CV_BGR2GRAY); // Convert image to gray 38 | // Show results 39 | imshow("Original", img); 40 | imshow("Crop", img_crop); 41 | imshow("Gray", img_gray); 42 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/t7i4gxhlerix.png] 43 | تبدیل تصویر رنگی ورودی دریافت شده از دوربین به تصویر طیف خاکستری و حذف بالا و پایین در تصویر روز (راست) و شب (چپ) 44 | یافتن خطوط خط کشی و جداسازی 45 | قبل از تشخیص لبه ها، به روشنی باید چیزی که در تصویر به دنبال اون هستیم رو مشخص کنیم. خط کشی جاده ها همیشه سفید یا زرد هستند. با نگاه بیشتر به تصاویر گرفته شده، یک روش ساده برای جداسازی خطوط خط کشی سفید، استخراج پیکسل هایی است که مقدار بیشتری نسبت به بقیه پیکسل های مجاور یا درون تصویر دارند. بنابراین نقاطی رو انتخاب می کنیم که مقداری کمی بیشتر از چارک بالای مقدار همه پیکسل های تصویر دارند. 46 | 47 | در ادامه چون رنگ زرد به آسانی قابل جداسازی در یک تصویر سه کاناله RGB نیست و ممکنه این مقادیر در حالت برداشت مقدار بر حسب چارک حذف بشند، فرمت نمایش تصویر رو به Hue, Saturation, Value یا HSV تبدبل میکنیم و نقاط نظیر با رنگ های زرد تصویر HSV رو در تصویر طیف خاکستری به عنوان نقاط مورد نظر استخراج می کنیم (برای یافتن طیف های رنگی می تونید از فتوشاپ یا این ابزار آنلاین استفاده کنید). نهایتا مجموع نقاط انتخاب شده سفید و زرد با اعمال یک فیلتر حذف نویز با میانگین گیری از پیکسل های همسایه، برای تحلیل های بعدی استفاده می شند. 48 | 49 | Mat mask_hsv_yellow, mask_white, img_mask; 50 | // Make target image by apply yellow and white mask 51 | Scalar m = mean(img_gray); 52 | cvtColor(img, mask_hsv_yellow, CV_BGR2HSV); 53 | inRange(img_crop, Scalar(20, 85, 85), Scalar(30, 255, 255), mask_hsv_yellow); 54 | inRange(img_gray, Scalar(m[0] + (255 - m[0]) / 3.5), Scalar(255), mask_white); 55 | bitwise_or(mask_white, mask_hsv_yellow, img_mask); 56 | GaussianBlur(img_mask, img_mask, cv::Size(5, 5), 0); 57 | imshow("Mask", img_mask); 58 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/ho4sxs3gp5ca.png] 59 | استخراج پیکسل های مورد نیاز برای شناسایی خط کشی های جاده در تصاویر روز (راست) و شب (چپ) 60 | تشخیص لبه های خطوط 61 | خُب، بعد از اینکه خطوط اصلی رو در تصویر حفظ کردیم و مقادیر دیگر رو حذف کردیم، باید لبه های اصلی خط کشی ها رو تشخیص بدیم. برای اینکار ابتدا باید به این سوال پاسخ بدیم: 62 | از نظر ریاضی در یک تصویر (یک ماتریس از مقادیر داده رنگی)، چه چیزی لبه رو تعریف می کنه؟ 63 | 64 | با نگاهی دقیق تر به داده های اطراف یک لبه، می تونیم به این نتیجه برسیم که لبه ها بخش هایی هستند که مقادیر پیکسل ها به سرعت تغییر می کنند. بنابراین تشخیص لبه، یافتن پیکسل هایی ای که در مقایسه با همسایه هاشون مقادیری به شدت متفاوت دارند. 65 | 66 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/i5udt6jlvcco.png] 67 | نمونه تشخیص خط کشی با استفاده از گرادیان تغییر مقادیر پیکسل ها برای یک لبه 68 | خوشبختانه در حوزه پردازش تصویر، این مسئله قبلا حل شده است. الگوریتم آشکارساز لبه Canny به همین روش و با یافتن مقادیر گرادیان در یک آستانه مشخص در طول تصویر اینکار رو انجام میده. بنابراین نیازی نیست که به مقادیر رنگ تصاویر فکر کنیم، تنها تغییرات مقدار برای ما اهمیت داره و می تونیم با این الگوریتم لبه ها رو در تصاویر مرحله قبل پیدا کنیم. 69 | 70 | Mat detected_edges, img_mask; 71 | int const max_lowThreshold = 255; 72 | int lowThreshold = 210, ratio = 3, kernel_size = 3; 73 | char* window_name = "Edge Map"; 74 | // CannyThreshold: Trackbar callback - Canny thresholds input with a ratio 1:3 75 | void CannyThreshold(int, void*){ 76 | blur(img_mask, detected_edges, Size(3, 3)); // Reduce noise with a kernel 3x3 77 | Canny(detected_edges, detected_edges, lowThreshold, lowThreshold * ratio, kernel_size); // Canny detector 78 | imshow(window_name, detected_edges); // Using Canny's output as a mask, and display our result 79 | } 80 | 81 | detected_edges.create(img_mask.size(), img_mask.type()); // Create a window 82 | namedWindow(window_name); 83 | createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold); // Create a Trackbar for user to enter threshold 84 | CannyThreshold(0, 0); // Show the image 85 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/2xozcs5nbo6c.png] 86 | نمونه خروجی برای الگوریتم آشکارساز لبه برای خط کشی های جاده در تصاویر روز (راست) و شب (چپ) 87 | تشخیص خطوط مسیر 88 | تا به اینجای کار، پیکسل هایی که لبه های خطوط رو نشون میدند، مشخص کردیم. حالا باید با اتصال این پیکسل ها به هم خطوط مشخص کننده مسیر رو تشخیص بدیم. مثل مرحله قبل این مسئله هم با یک تئوری ریاضی قابل حل هست. بیایید دوباره نگاهی به لبه های یافته شده بیاندازیم: 89 | 90 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/xn7nneda0k5k.png] 91 | لبه یافته شده در یک ناحیه مشخص شده (سبز)؛ خطوط کاندید برای لبه با رنگ آبی در تصویر مشخص شده است. 92 | 93 | با نگاه نزدیک به لبه ها، مشخصه که بهترین خطی که یک لبه رو نمایش میده، خطی است که بیشترین تعداد پیکسل از لبه رو هم شامل میشه (خط ب در تصویر بالا). یافتن این خط یک مسئله دشوار هست. چرا که ممکنه تعداد این خطوط خیلی زیاد باشه و نیاز هست تا تمام خط های ممکن بررسی بشند. 94 | 95 | برای این منظور می تونیم از تبدیل هاف استفاده کنیم. در این تبدیل، ما تمام پیکسل های لبه رو به یک فرم نمایش ریاضی دیگه تبدیل میکنیم. بعد از تبدیل کامل، هر پیکسل در "فضای تصویر" به یک خط یا منحنی در "فضای هاف" تبدیل می شه؛ یعنی در فضای هاف هر خط به شکل یک نقطه در تصویر نمایش داده میشه. 96 | 97 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/al8j6npxelqr.png] 98 | نمایشی از فضای تصویر و فضای هاف متناظر به همراه پارامترها (منبع) 99 | بنابراین ما نیازی به حل مسئله یافتن خطی که از همه پیکسل های همسایه عبور کنه نداریم و تنها کافی است خطی رو پیدا کنیم که در فضای هاف هست و نهایتا این خط رو به فضای تصویر نگاشت کنیم. 100 | 101 | Mat img_hlines = img_crop.clone(); 102 | // Standard Hough Line Transform 103 | vector lines; // will hold the results of the detection 104 | HoughLinesP(detected_edges, lines, 1, CV_PI / 180, 50, 30, 10); // runs the actual detection 105 | // Draw the lines 106 | for (size_t i = 0; i < lines.size(); i++) { 107 | Vec4i l = lines[i]; 108 | line(img_hlines, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 255), 2, CV_AA); 109 | } 110 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/kkhl364gvhxh.png] 111 | خطوط یافت شده (زرد) با استفاده از پیکسل های لبه بعد از نگاشت از فضای هاف به فضای تصویر و قرار گرفته بر روی تصاویر اصلی 112 | گروه بندی و تصمیم گیری 113 | در مرحله آخر پردازش تصاویر، هدف ایجاد یک معیار برای تصمیم گیری است. اگر تا اینجا همه چیز درست پیاده سازی شده باشه، خطوطی خواهیم داشت که نماینده ای از خط کشی جاده برای مسیری هستند که در حال عبور از اون هستیم. ابتدا این خطوط رو به دو دسته خط کشی سمت راست و چپ تقسیم می کنیم. یک تفاوت آشکار بین دو گروه از خط ها، جهت شیب این خطوط است. اندازه شیب هر خط زاویه رو اندازه می گیره. خطوط افقی شیب صفر و خطوط عمودی شیب بینهایت دارند. پس شیب خط های یافته شده اندازه ای بین این دو مقدار دارند، چراکه اون ها از پایین تصویر به سمت مرکز، نسبت به افق زاویه دارند. 114 | 115 | جهت شیب یک خط نشون میده که با حرکت از چپ به راست، آیا خط به بالا متمایل است یا پایین؟ خطوط با شیب منفی به سمت پایین و خطوط با شیب مثبت به بالا حرکت می کنند. این همان چیزی است که در سیستم مختصات عادی اتفاق می افته. در سیستم مختصاتی که ما از اون استفاده می کنیم، نقطه مرکز در گوشه بالا سمت چپ تصویر هست؛ یعنی در اینجا جهت شیب ما معکوس خواهد بود. 116 | 117 | پس خط های سمت راست شیب مثبت دارند و به پایین حرکت می کنند. مشاهدات نشون میدند که خطوطی که شیب خیلی کمی دارند احتمالا خطوط خوبی برای یافتن خط تصمیم گیری نیستند. بنابراین سعی می کنیم از این بین خطوطی که شیبی بیشتر/کمتر از 0.4 (+/-) دارند رو انتخاب کنیم. 118 | 119 | bool less_left(const Vec4i& lhs, const Vec4i& rhs){ return lhs[0] < rhs[0]; } 120 | bool less_right(const Vec4i& lhs, const Vec4i& rhs) { return lhs[0] > rhs[0]; } 121 | vector rightls, leftls; 122 | // Calculating the slope and group lines 123 | float slope = (float)(l[3] - l[1]) / (l[2] - l[0]); 124 | if (slope > 0.40) { rightls.push_back(l); }else if (slope < -0.40) { leftls.push_back(l); } 125 | // Find regions 126 | Point left_b, left_t, right_b, right_t; 127 | if (leftls.size() > 0) { 128 | auto lmmx = minmax_element(leftls.begin(), leftls.end(), less_left); 129 | left_b = Point(get<0>(lmmx)[0][0], get<0>(lmmx)[0][1]); 130 | left_t = Point(get<0>(lmmx)[0][2], get<0>(lmmx)[0][3]); 131 | } 132 | if (rightls.size() > 0) { 133 | auto rmmx = minmax_element(rightls.begin(), rightls.end(), less_right); 134 | right_t = Point(get<0>(rmmx)[0][0], get<0>(rmmx)[0][1]); 135 | right_b = Point(get<0>(rmmx)[0][2], get<0>(rmmx)[0][3]); 136 | } 137 | 138 | Mat poly = img_hlines.clone(); 139 | vector vertices{ left_b, left_t, right_t, right_b }; 140 | vector> pts{ vertices }; 141 | fillPoly(poly, pts, Scalar(58, 190, 37, 0)); 142 | addWeighted(poly, 0.50, img_hlines, 0.50, 0, img_hlines); 143 | 144 | // Find reference line points by average top and bottom middle 145 | float rx = (((right_b.x - left_b.x) / 2 + left_b.x) + ((right_t.x - left_t.x) / 2 + left_t.x)) / 2, ry = img_hlines.rows; 146 | // Draw dashed reference line 147 | Point p1(rx, 0), p2(rx, ry); 148 | LineIterator itl(img_hlines, p1, p2, 8); 149 | for (int i = 0; i < itl.count; i++, itl++) { 150 | if (i % 5 != 0) { (*itl)[1] = 80; (*itl)[2] = 75; } 151 | } 152 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/rfc62aux5zpv.png] 153 | نتیجه نهایی پردازش تصویر برای یافتن خط تصمیم گیری میزان انحراف خودرو از جاده (خط چین) در شب (بالا) و روز (پایین) 154 | 155 | خط تصمیم گیری که نماینده ای از انحراف خودرو از مسیر در حال حرکت هست، میانگینی از دو گروه است. برای این خط، مقدار میانگین بیشترین و کمترین x از هر گروه، مشخص کننده مقدار x خواهد بود. 156 | 157 | آخرین مرحله در اینجا دریافت تصاویر از دوربین هست. کافیه تا هر فریم (Frame) از ویدیو به صورت جداگانه دریافت شده و تمام مراحل بالا برای اون تکرار بشه. البته در مورد ویدیو میشه با دقت بیشتری اشیا مختلف رو دنبال کرد یا هر فریم رو در بازه زمان و نسبت به بقیه فریم ها در نظر گرفت که در اینجا به علت طولانی شدن مطلب به اون نمی پردازیم. اگر علاقمندید که این تصاویر رو از طریق شبکه بین موبایل و لپ تاپ دریافت کنید هم می تونید این کدها رو بررسی کنید. 158 | 159 | VideoCapture cap(0); // open the camera 160 | if(!cap.isOpened()) return -1; // check if we successfully connected to camera 161 | for(;;) { 162 | Mat frame; 163 | cap >> frame; // get a new frame from camera and start processing 164 | // Our codes ... 165 | if(waitKey(30) >= 0) break; 166 | } 167 | ما موفق شدیم! الان سیستمی داریم که می تونه مسیر خودرو رو تشخیص بده. کافیه با توجه به محل قرارگیری دوربین در جلو خودرو، در صورتیکه انحراف این خط بیشتر از میزان کالیبره شده بود؛ یعنی خودرو به صورت ناگهانی تغییر مسیر داد، فرمان های هشدار به راننده داده بشه. 168 | 169 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/mvojtttv26vr.gif] 170 | سیستم تشخیص تغییر مسیر راننده با بهره گیری از بینایی کامپیوتر برای تصاویر واقعی از رانندگی در شب 171 | اما منظور از فرمان هشدار چیه؟ در ادامه می خوایم به همین سوال پاسخ بدیم. 172 | 173 | بدون شک کاندیدای اول برای ارتباط با سامانه های الکترونیکی خودرو پورت OBD-II هست. بعد از سال 2004 تمام تولیدکنندگان اروپایی برای کاهش کابل های داخلی خودرو موظف به قرار دادن این پورت در تولیدات خود شدند که یک رابط استاندارد برای دریافت اطلاعات مختلف (مثل ولتاژ باتری، دمای روغن، دور موتور و ...) و عیب یابی (Diagnostics) خودرو است. در خودروهای جدیدتر، این پورت به عنوان یک یونیت (Unit) در باس کن (CAN bus) با دیگر بخش های داخلی خودرو در ارتباط هست. بنابراین می شه از طریق اون اطلاعات رد و بدل شده روی شبکه داخلی خودرو رو رصد کرد یا با ارسال برخی فرامین با یونیت های داخل خودرو ارتباط داشت. تمام نود (Node) ها از طریق دو رشته سیم با نام CAN high یا CANH و CAN low یا CANL که به این شبکه متصل شده اند با هم صحبت می کنند و فریم (Frame) های ارسالی همراه با یک ID عددی برای جداسازی هر فریم و حداکثر 8 بایت داده ارسال می شوند. CAN از دیفرانسیل سیگنالینگ استفاده می کنه؛ یعنی به ازای هر افزایش مقدار سیگنال روی یکی از خط ها به همان میزان مقدار رو روی خط دیگه کاهش میده. از این روش در محیط های پر نویز برای افزایش تحمل خطای سیستم استفاده میشه. 174 | 175 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/hq0nzcq16hsa.png] 176 | قالب بیت های داده در بسته های CAN استاندارد 177 | 178 | تا اونجاییکه می دونم، اطلاعات آنلاین زیادی از اطلاعات CAN برای رانا روی اینترنت پیدا نمیشه. محتویات هر فریم به صورت عمومی ثبت نشدند و با توجه به کارخونه سازنده منحصر بفرد هستند. پس تصمیم گرفتم برخی از جزئیات دسترسی اطلاعات خودروها رو از طریق منبع کدهای این مطلب به صورت عمومی منتشر کنم. 179 | 180 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/tuqq5uxbp1jx.png] 181 | شمای نودهای مختلف در خودرو رانا با سیستم مالتی پلکس ECO MUX 182 | 183 | خودروی رانای ما با موتور TU5 مجهز به شبکه مالتی پلکس با پنج نود FCM یا Front Control Module در قسمت جلوی راننده برای کنترل چراغ ها و محدوده جلو خودرو، ICN یا Instrument Cluster Node برای کنترل بخش های مختلف جلو آمپر و BCM یا Body Control Module در داشبورد برای مدیریت قفل مرکزی، درها و شیشه بالابر که تحت پروتکل CAN Low Speed با هم در ارتباط هستند. در این سیستم BCM دستوراتی که روی سیستم اهرم های پشت فرمان به صورت آنالوگ دریافت میکنه رو به صورت دیجیتال به دستورات شبکه تبدیل میکنه تا بقیه نودها اون ها رو دریافت کنند و این نود به عنوان رابط عیب یابی مستقیما با پورت OBD در ارتباط هست. همچنین در خودرو ما ECU ی موتور و یونیت ABS در یک شبکه با استاندارد CAN High Speed هستند. 184 | ما می خوایم برای زمانیکه راننده از مسیر اصلی منحرف میشه یک هشدار ایجاد کنیم. با ساختاری که در بالا توضیح داده شد، چراغ های هشدار مربوط به راهنما در صفحه نمایش جلو داشبورد (جلو آمپر) یک انتخاب خوب هستند. پس سعی میکنیم با هک شبکه و ارسال فریم مربوط به روشن و خاموش شدن چراغ های راهنمای سمت راست و چپ در جلو داشبورد ، به راننده زمانیکه به صورت ناگهانی از مسیر خارج شد، اخطار بدیم. بنابراین اگر خودرو از مسیر اصلی منحرف بشه، راننده بدون اینکه راهنما زده باشه، چراغ راهنمای سمت مورد نظر رو روی صفحه نمایش میبنه. 185 | 186 | طبق نقشه ها، اطلاعات دسته راهنما به صورت آنالوگ تحلیل میشه؛ یعنی این اهرم با تغییر سطح سیگنال حالت فعلی رو به BCM اطلاع میده. از طرفی میدونیم که اطلاعات چراغ های راهنما از BCM به ICN در شبکه ارسال میشه. چون پورت OBD خودرو ما به صورت مستقیم در شبکه حضور نداره و به BCM متصل هست، برای دسترسی به اطلاعات شبکه با وصل شدن به عنوان فرد میانی (man-in-the-middle) مقادیر فریم های داخل باس رو شنود می کنیم. با کمی جستجو در مستندات و نقشه ها، در میابیم که سیگنال های داده شبکه مورد نیاز ما از BCM قابل ارسال و دریافت هستند. پایه 1 و 2 کانکتور 18 پایه سفید روی BCM به ترتیب مربوط به CANH و CANL هستند. نحوه دسترسی به BCM و محل کانکتور 18 پایه در شکل زیر مشخص شده اند. 187 | 188 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/ealuptkdlupn.png] 189 | اتصالات و محل نود BCM داخل خودرو رانا با سیستم ECO MUX؛ دسترسی از زیر داشبورد بالای پای راننده، کنار جعبه فیوز داخل اتاق 190 | برای دسترسی به داده ها می تونیم از کانکتورهای T استفاده کنیم یا با خراش دادن بخشی از روکش سیم با سیم دیگری داده ها رو دریافت کنیم. چون زمانبندی و مقادیر داده فریم های ارسالی در شبکه نباید تحت تاثیر قرار بگیره، پس برای دریافت داده ها از سیم ها از روش T استفاده میکنیم. سطح سیگنال CAN بین 1.25 تا 3.75 ولت هست، برای خواندن این مقادیر در سطح دیجیتال، از فرستنده و گیرنده TJA1050 کمک گرفته و خروجی رو با MAX232 و FT2232 از طریق کابل USB دریافت می کنیم. اگر همه چیز تا به اینجا خوب پیش رفته باشه، داده های ارسالی از پورت USB با درایور مربوطه از طریق یک پورت سریال مجازی قابل دریافت هستند. 191 | 192 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/fbosabxndmt5.png] 193 | نحوه برقراری ارتباط برای دریافت و ارسال داده ها از طریق کانکتور T (قرمز رنگ) بر روی سوکت نری (سفید رنگ) BCM خودرو ما 194 | بعد از آماده سازی سخت افزاری برای دریافت داده ها، سعی میکنیم داده ها رو دریافت کنیم. برای این منظور برنامه ای می نویسیم که داده های پورت سریال رو بخونه و تحلیل کنه. طبق توضیحات بالا، فریم های CAN بر اساس استاندارد مشخصی تولید میشند. طبق استاندارد هر فریم با مقدار 0X7F تموم میشه و فریم ها شامل ID منحصر بفرد هستند؛ بنابراین می تونیم هر فریم رو با مقدار انتهایی و ID اون ها شناسایی کرده و دیگر بخش های فریم رو جداسازی کنیم. هر نود در شبکه CAN داده های خودش رو در یک بازه زمانی در شبکه ارسال میکنه و در هر لحظه مقادیر زیادی داده روی شبکه وجود داره. این نکته هم حائز اهمیت هست که اگر به شبکه CAN پرسرعت متصل هستیم با معماری سخت افزاری که توضیح داده شد، چون سرعت سریال کمتر از میزان داده های دریافتی هست، ممکنه بخشی از داده ها از بین بره که باید این مورد رو هم توی برنامه در نظر بگیریم. 195 | 196 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/rtvkwrpecb08.gif] 197 | برنامه نوشته شده با قابلیت نمایش داده های دریافتی، جداسازی اطلاعات فریم ها و ارسال داده های دلخواه در شبکه 198 | با این برنامه، داده های شبکه بلادرنگ قابل تشخیص و جداسازی هستند. در صورتیکه فریم جدیدی در شبکه ارسال بشه، در ستون سمت چپ مشخص میشه. حالا نوبت این رسیده که فریم های مربوط به دستور روشن شدن چراغ راهنمای سمت راست و چپ در صفحه نمایش جلو آمپر رو پیدا کنیم. این فریم ها زمانی به جلو آمپر ارسال میشند که دسته راهنما در کنار فرمان به بالا و پایین حرکت داده بشه. پس کافیه در حالتیکه برنامه در حال اجرا هست، اهرم رو به طرفین حرکت داده و فریم های مربوطه رو دریافت کنیم. 199 | 200 | سیستم هوشمند ما با آخرین مرحله کامل میشه اگر این فریم ها رو به صورت جداگانه زمانیکه خودرو از مسیر اصلی منحرف شد، برای جلوآمپر ارسال میکنیم تا راننده از تغییر مسیر خودرو مطلع شود. 201 | 202 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/uuqkcnjtrbpz.gif] 203 | ارسال فرمان های روشن شدن چراغ های راهنمای راست و چپ برای زمانیکه راننده از مسیر منحرف میشه 204 | این مطلب به صورت کامل از طریق گیت هاب و مطلب قبلی از اینجا در دسترس هست. همچنین اگر علاقمند به موضوعات هوش مصنوعی، یادگیری ماشین و بینایی کامپیوتر هستید می تونید من رو در توییتر دنبال کنید. 205 | 206 | [https://files.virgool.io/upload/users/7843/posts/rkgz4q8v37xg/edawmiqfprqi.gif] 207 | ماشین خودکار هوشمند برای بازی کمپین دیجیکالا، تخفیفان و شاتل از توییتر 208 | 209 | از تمامی عزیزانی که در چند هفته پیاده سازی و نگارش این مطلب راهنمایی هاشون راهگشای من بود، صمیمانه تشکر میکنم. خوشحال میشم اگر مطلب رو پسندید با بقیه به اشتراک بذارید و 🧡 کنید. 210 | این ماجراجویی تموم شد. حالا نوبت شماست که سیستم هوشمند خودتون رو طراحی کنید و تجربیاتتون رو به اشتراک بذارید. به نظر شما چالش های ایجاد یک خودروی خودران هوشمند چیه؟ 211 | 212 | 213 | http://vrgl.ir/Eu7UE 214 | 215 | #بینایی کامپیوتر #هوش مصنوعی#یادگیری ماشین#هک خودرو#هک -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/206_Multiplex_Intro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/206_Multiplex_Intro.pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/Emdad_Rana_Peugeot206_New.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/Emdad_Rana_Peugeot206_New.pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/IKCO_Rana_Multiplex_Nodes_Configuration_Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/IKCO_Rana_Multiplex_Nodes_Configuration_Manual.pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/IKCO_Rana_officialBooklet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/IKCO_Rana_officialBooklet.pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/ISACO_IKCO_NewMUX_SAMAND_RANA_DENA_PARS_Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/ISACO_IKCO_NewMUX_SAMAND_RANA_DENA_PARS_Manual.pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/Introduction to the Controller Area Network (CAN).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/Introduction to the Controller Area Network (CAN).pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/MultiPlex_Samand_Soren_Rana_206_EmdadKhodro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/MultiPlex_Samand_Soren_Rana_206_EmdadKhodro.pdf -------------------------------------------------------------------------------- /how-to-build-an-intelligent-car-with-image-processing/documents/TPCAN 207 Sport pack.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-build-an-intelligent-car-with-image-processing/documents/TPCAN 207 Sport pack.pdf -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/FindPhotosFaster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/FindPhotosFaster.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/acc_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/acc_table.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/cover.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/dataset_airplane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/dataset_airplane.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/dataset_nonairplane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/dataset_nonairplane.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/full_conv_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/full_conv_model.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/fullimage_tiles_processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/fullimage_tiles_processing.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/generated_samples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/generated_samples.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/hoda_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/hoda_sample.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/max-pooled_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/max-pooled_array.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/model.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_center.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_toppng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_toppng.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win.gif -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win1.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win10.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win11.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win2.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win3.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win4.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win5.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win6.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win7.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win8.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/nn_model_win9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/nn_model_win9.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/num_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/num_gif.gif -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/num_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/num_img.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/num_num.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/num_num.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/num_num_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/num_num_grid.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/num_zeros.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/num_zeros.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/pic.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/pic.JPG -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/pic_conv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/pic_conv.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/sample_faltten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/sample_faltten.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/sample_faltten_zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/sample_faltten_zero.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/sample_sat_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/sample_sat_img.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/sample_six.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/sample_six.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/sample_three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/sample_three.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/tile_conv_processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/tile_conv_processing.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/training_charts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/training_charts.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/tweet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/tweet.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/assets/yolo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkhojasteh/Personal-Blog/ccf6f9a154689e3a24e91650fe119dc35636bee8/how-to-find-airplane-in-images/assets/yolo.png -------------------------------------------------------------------------------- /how-to-find-airplane-in-images/blog post.txt: -------------------------------------------------------------------------------- 1 | چطوری با بینایی کامپیوتر هواپیماها رو در تصویر هوایی پیدا کنیم؟ 2 | 3 | اگر شما هم از کسانی هستید که از خوندن مطالب طولانی و پیچیده در مورد هوش مصنوعی، یادگیری عمیق و شبکه‌های عصبی کانولوشنال خسته شدید و واقعا نمی‌دونید این شبکه‌ها چه تفاوتی با شبکه‌های عصبی دیگه دارند، این مطلب برای شماست. 4 | 5 | این‌بار می‌خواهیم یاد بگیریم که چطور برنامه‌هایی رو بنویسیم که اشیا رو در تصاویر با استفاده از یادگیری عمیق تشخیص بده و مدلی طراحی خواهیم کرد که در تصاویر هوایی هواپیماها رو پیدا میکنه. همچنین در این پست قصد داریم با رویکرد آموزشی یاد بگیریم که شبکه های عصبی کانولوشنال (پیچشی) چطور کار می‌کنند. یکی از کاربرد‌های این روش که ممکن است روزانه از اون استفاده کنیم جستجوی یک کلمه در اپلیکیشن گوگل فوتوز بر اساس تصویر است. 6 | 7 | تنها با جستجوی یک کلمه یا ایموجی می‌توان در بین تمام تصاویری که قبلا برچسب‌گذاری نشده‌اند، جستجو کرد. مثلا با نوشتن کلمه 'سگ' میشه تمام تصاویر شامل این شی رو پیدا کرد. این کار واقعا چطور انجام می‌شود؟ 8 | تنها با جستجوی یک کلمه یا ایموجی می‌توان در بین تمام تصاویری که قبلا برچسب‌گذاری نشده‌اند، جستجو کرد. مثلا با نوشتن کلمه 'سگ' میشه تمام تصاویر شامل این شی رو پیدا کرد. این کار واقعا چطور انجام می‌شود؟ 9 | این راهنما برای کسانی است که برای یادگیری هوش مصنوعی کنجکاو هستند اما ایده‌ای برای شروع ندارند. بنابراین بدون توجه به جزئیات اضافی، سعی می‌کنیم تا یک مسئله رو با یادگیری عمیق حل کنیم. اگر علاقمند به یادگیری ماشین و بینایی کامپیوتر هستید، مطالب قبلی رو از دست ندید. 10 | 11 | واقعیت اینه که یک کودک سه ساله به راحتی می‌تونه یک عکس از هواپیما رو تشخیص بده، اما حل این مسئله که کامپیوتر چطور میتونه هواپیما رو در عکس تشخیص بده، بهترین دانشمندان کامپیوتر رو بیش از ۵۰ سال گیج کرده بود. سرانجام در چند سال گذشته، یک رویکرد خوب در هوش مصنوعی برای شناسایی اشیا با استفاده از شبکه‌های عصبی عمیق کانولوشنال پیدا شده است. این ایده‌ها ابتدا بسیار پراکنده بودند، اما بعدتر با کنار هم‌گذاشتن اون‌ها بهترین ماشین‌های تشخیص تصاویر ایجاد شدند. پس بیاید در ماجراجویی این بار، ماشینی رو درست کنیم که اشیا رو در تصاویر تشخیص میده. 12 | 13 | شروع ساده 14 | قبل از اینکه بخواییم اشیا پیچیده رو در تصاویر پیدا کنیم، بیایید ببینیم چطور میتونیم اعداد دست‌نویس در تصاویر رو تشخیص بدیم. در اینجا هم مثل شکستن کپچای سیستم گلستان با کمک یک شبکه عصبی و یادگیری ماشین این مسئله را حل خواهیم کرد. این شبکه از تعداد زیادی نورون ساده که زنجیروار به هم متصل شده‌اند، تشکیل شده است. هر نورون با دریافت یک ورودی و در نظرگرفتن یک وزن (ضرب)، و اعمال یک تابع، خروجی را مشخص میکند. با کنار هم‌گذاشتن تعداد زیادی از این سلول‌های ساده یک مدل پیچیده برای تشخیص خواهیم داشت. یک نورون مثل لوگو و مدل پیچیده مثل تعداد زیادی لگو ساده هستند که روی هم چیده‌شده‌اند تا نهایتا یک وظیفه رو بر عهده بگیرند؛ یعنی اگر تعداد زیادی لگو با رنگ‌ها و شکل‌های متخلف داشته باشیم، می‌تونیم هرچیزی رو بسازیم! در کنار شبکه عصبی ما یادگیری ماشین رو داریم که یک الگوریتم عمومی است که با تغییر داده‌های وورودی در حل مسائل مختلف کاربرد دارد. پس در اینجا یک شبکه عصبی با کمی تغییر مشابه همان چیزی که ساختیم، اعداد دست‌نویس را تشخیص می‌دهد. 15 | 16 | واقعیت این است که یادگیری ماشین تنها زمانی کار می‌کند که داده‌های کافی و مناسب داشته باشیم. پس برای شروع نیاز به تعداد زیادی تصویر از اعداد دست‌نویس داریم. به لطف مجموعه ارقام هدی، در حال حاضر تعداد زیادی تصویر از اعداد برای استفاده تحقیقاتی موجود است. این مجموعه بزرگ ارقام دستنویس فارسی، شامل ۱۰۲۳۵۳ نمونه دست‌نوشته سیاه و سفید است. داده های این مجموعه از حدود ۱۲۰۰۰ فرم ثبت نام آزمون سراسری کارشناسی ارشد و آزمون کاردانی در سال ۱۳۸۳ استخراج شده است. در واقع هر عدد یک تصویر ۲۸ در ۲۸ پیکسل است. در ادامه نمونه هایی از اعداد این مجموعه آمده است. 17 | 18 | نمونه‌هایی از اعداد نوشته‌شده با دست‌خط‌های مختلف در مجموعه ارقام دست‌نویس 19 | نمونه‌هایی از اعداد نوشته‌شده با دست‌خط‌های مختلف در مجموعه ارقام دست‌نویس 20 | نمونه‌ها در ده کلاس شامل عدد صفر تا نُه هستند و درجه تفکیک تصاویر ۲۰۰ نقطه بر اینچ و در کیفیت‌های مختلف در دسترس است. همچنین دسته‌بندی اولیه برای داده‌های آموزشی و تست موجود است. 21 | 22 | ورودی تصویر یا عدد؟ مسئله این است! 23 | می‌دونیم که شبکه‌های عصبی فقط تعدادی عدد به عنوان ورودی می‌پذیرد. ولی ما در اینجا می‌خواهیم تصاویر را به عنوان ورودی در‌نظر بگیریم. خب سوال این است که تصاویر چگونه در شبکه پردازش می‌شوند؟ پاسخ ساده است. برای کامپیوتر هر تصویر یک ماتریس از اعداد بین ۰ تا ۲۵۵ است که این عدد نشان می‌دهد هر پیکسل چقدر تیره است. 24 | 25 | یک نمونه نمایش تصویر از عدد سه دست‌نویس همراه با نمایش ورودی عددی برای شبکه به‌ازای روشنایی هر پیکسل 26 | یک نمونه نمایش تصویر از عدد سه دست‌نویس همراه با نمایش ورودی عددی برای شبکه به‌ازای روشنایی هر پیکسل 27 | ما می‌تونیم یک ماتریس ۲۸ در ۲۸ رو به صورت یک آرایه ۷۸۴ تایی از اعداد به عنوان ورودی شبکه عصبی در نظر بگیریم. بنابراین مدل ما باید ۷۸۴ عدد ورودی بگیرد و ما به ازای هر گروه از ورودی یک خروجی تولید کند. با داشتن خروجی جداگانه برای هر نوع شی که می‌خواهیم تشخیص دهیم، می‌تونیم از شبکه برای طبقه‌بندی اشیا به گروه‌ها استفاده کنیم. منظور از گروه حالت‌های خروجی برای مدل است. مثلا مدل می تواند ۱۰ حالت خروجی برای اعداد داشته باشد یا تنها یک حالت داشته باشد که با یک عدد اعشاری بین صفر و یک احتمال سه بودن عدد داخل تصویر را مشخص می‌کند. برای سادگی فعلا فرض کنید شبکه ما یک خروجی دارد. 28 | 29 | حالا نیاز است که شبکه رو طراحی کنیم. در طراحی معماری؛ یعنی نحوه اتصال نورون‌های مختلف به‌هم، نکات و جزئیات زیادی حائز اهمیت است که شاید در یک مطلب دیگر به آن بپردازیم. اما در مورد اندازه یا تعداد نورون‌ها، شبکه می‌تواند بسیار بزرگ باشد. جالبه که بدونیم کامپیوترهای امروز می تونند محاسبات پردازش تصاویر رو در شبکه‌هایی با چندصد نود یا نورون بدون وقفه انجام دهند. حتی بسیاری از تلفن‌های همراه امروز نیز از پس اجرای دستورات محاسباتی این مدل‌ها بر می‌آیند. اگر علاقمندید تا در این مورد بیشتر بدونید، قبلا یک مدل با دقت بالا برای تشخیص این ارقام در کارگاه کنفرانس موضوعات معاصر در علوم داده ساختیم که می تونید در گیت‌هاب پیدا کنید. 30 | 31 | یافتن عدد دست‌نویس در تصاویر 32 | خیلی خوب بود اگر فقط تصویر رو به صورت آرایه‌ای از اعداد برای شناسایی به یک شبکه می دادیم. اما عملا این اتفاق نمی‌افته. خبر خوب اینه که اگر وزن‌های نورون‌ها در مدل به درستی تعیین شده باشه و عدد به درستی در وسط تصویر نوشته شده باشد، مدل کار میکنه: 33 | 34 | شبکه عصبی مصنوعی تصویر ورودی سه که در مرکز تصویر است را به درستی تشخیص می‌دهد. 35 | شبکه عصبی مصنوعی تصویر ورودی سه که در مرکز تصویر است را به درستی تشخیص می‌دهد. 36 | اما خبر بد اینه که اگر عدد به درستی در وسط تصویر نباشد، خروجی چندان رضایت بخش نخواهد بود. فقط کوچک‌ترین تغییری همه چیز رو خراب می‌کنه: 37 | 38 | مدل آموزش داده‌شده، به علت تغییر عدد ورودی با جابجایی تصویر، نمی‌تواند عدد را تشخیص دهد. 39 | مدل آموزش داده‌شده، به علت تغییر عدد ورودی با جابجایی تصویر، نمی‌تواند عدد را تشخیص دهد. 40 | دقت کم در این حالت به این خاطر است که شبکه تنها الگوی عدد سه زمانی‌که در میانه تصویر است را یاد گرفته است. در واقع هیچ ایده‌ای ندارد که اگر سه در تصویر جابجا شود، ممکن است اعداد ورودی به چه صورتی تغییر کنند. این مدل در دنیای واقعی چندان کاربردی ندارد. مشکلات دنیای واقعی هرگز تمیز و ساده نیستند. بنابراین ما باید بفهمیم که چگونه شبکه عصبی خود را در مواردی که عدد کاملا در مرکز نیست، آموزش دهیم. 41 | 42 | ایده اول؛ جستجو در تصویر 43 | 44 | تا به اینجا یک مدل خوب برای شناخت عدد سه وقتی‌که عدد در مرکز تصویر باشد، طراحی کردیم. به نظر می رسد تنها کافیست در یک پنجره کوچک‌تر در تصویر به دنبال عدد بگردیم. با اینکار در صورتی‌که عدد در تصویر باشد حتما در یک بخش از تصویر حضور خواهد داشت. 45 | 46 | جستجو اعداد در پنجره‌های کوچک‌تر در تصویر 47 | جستجو اعداد در پنجره‌های کوچک‌تر در تصویر 48 | این رویکرد به پنجره کشویی (روان) یا Sliding Window معروف است که کاملا غیرهوشمندانه یا Brute-force است. این روش در موارد محدودی کار می‌کند ولی در موارد زیادی واقعا ناکارآمد است. چون باید این کار را برای تمام بخش‌های یک تصویر در اندازه‌های مختلف چند بار امتحان کنیم؛ یعنی باید از قبل بدانیم چه اندازه پنجره‌ای برای پیدا‌کردن عدد مناسب است یا اندازه‌های زیادی را امتحان کنیم. بنابراین بهتر است ایده‌های دیگری رو هم درنظر بگیریم. 49 | 50 | ایده دوم؛ داده‌های بیشتر برای آموزش 51 | 52 | ما شبکه را با عدد سه در مرکز تصاویر آموزش دادیم. شاید اگر مدل با انواع مختلفی از عدد در اندازه‌ها و مکان‌های مختلف تصویر آموزش داده شود، بتواند این عدد را در حالتی غیر از مرکز تصویر نیز شناسایی کند. پس نیاز به مجموعه‌ی تصاویری با ویژگی‌های جدید مثل اندازه‌های مختلف از یک عدد یا اعدادی با اندازه‌های متفاوت داریم. برای این‌کار نیازی به تصاویر جدید آموزشی نداریم. کافی است از همان اعداد قبلی برای ساخت تصاویر جدید با حالت‌های مختلف استفاده کنیم. 53 | 54 | داده‌های آموزشی مصنوعی ساخته شده با نسخه‌های مختلف از تصاویر آموزشی که قبلا در مجموعه داشتیم. 55 | داده‌های آموزشی مصنوعی ساخته شده با نسخه‌های مختلف از تصاویر آموزشی که قبلا در مجموعه داشتیم. 56 | با استفاده از این روش، می‌تونیم به راحتی یک منبع عظیم از داده‌های آموزشی ایجاد کنیم. داده‌های بیشتر یادگیری را برای شبکه عصبی ما سخت‌تر میکند، اما ما می‌تونیم با افزایش تعداد نورون‌ها در شبکه، این مسئله را جبران کنیم و در نتیجه قادر به یادگیری الگوهای پیچیده‌تر باشیم. برای این‌کار تعداد لایه‌های شبکه را افزایش می‌دهیم. بنابراین ما این مدل را شبکه عصبی عمیق می‌نامیم زیرا لایه‌های بیشتری از یک شبکه عصبی سنتی دارد. 57 | 58 | این ایده از اواخر دهه ۱۹۶۰ تا کنون بوده‌است. اما تا همین اواخر، آموزش یک شبکه بزرگ عصبی برای استفاده مفید بسیار کُند بود. محققان زمانی که فهمیدند چگونه از کارت گرافیکی (که برای انجام ضرب ماتریس‌ها واقعا سریع طراحی شدند.) به جای پردازنده‌های معمولی کامپیوتر استفاده کنند، پردازش با شبکه‌های عصبی بزرگ عملی شد. در واقع همان کارت گرافیکی که برای اجرای بازی کاربرد دارد، می تواند برای آموزش سریع یک شبکه عصبی عمیق استفاده شود. با اینکه ما می‌تونیم شبکه عصبی خود را واقعا بزرگ کنیم و آن را به سرعت با یک کارت گرافیکی آموزش دهیم، هنوز راه‌حل خوبی برای حل مسئله نیست. بهتر است برای پردازش تصاویر کمی هوشمندانه عمل کنیم. حتما راه‌حل بهتری به جای استفاده از چندین نمونه مشابه تنها با تغییر مکان عدد در تصویر و صرف زمان زیاد وجود داره. 59 | 60 | کانوُلوشِن 61 | به طور شهودی می‌دونیم که تصاویر دارای یک سلسله‌مراتب یا ساختار مفهومی هستند. این تصویر را ببینید: 62 | 63 | ماچِکول؛ تصویر مارمولک زیبایی که در یکی از سفرهایم ملاقات کردم. 64 | ماچِکول؛ تصویر مارمولک زیبایی که در یکی از سفرهایم ملاقات کردم. 65 | به عنوان یک انسان، شما فورا مفاهیم سلسله‌مراتبی را در این تصویر تشخیص می‌دهید: زمینی پوشیده از خاک و گیاهان، مارمولک زیبای سبز رنگ، مارمولک روی یک سنگ لَم داده است و سنگی که روی خاک و علف‌زار است. ما از کودکی یادگرفتیم که مفهوم مارمولک فارغ از آنچه که روی آن نشسته است تعریف می‌شود و به ازای هر سطح متفاوت یکبار این مفهوم را مجددا بازنگری نمی‌کنیم. کاری که در حال حاضر، شبکه عصبی ما نمی‌تواند انجام دهد. مدل فکر می‌کند عدد در هر بخش از تصویر یک مفهوم متفاوت است و نمی‌داند که مکان عدد تاثیری در ماهیت آن ندارد و این یعنی هربار باید دوباره مفهوم را در یک مکان جدید در تصویر یاد بگیرد. همچنین شبکه‌ای که تا به اینجا آموزش داده شده است اعداد را در یک پس‌زمینه سفید یاد می‌گیرد که همیشه اینطور نیست. پس بهتر است مدل نیز یک مفهوم از اشیا را یاد بگیرد. برای این‌کار باید از مفهومی به اسم کانوُلوشِن کمک بگیریم. ایده استفاده از کانولوشن برای جل این مسئله، تا حدی از علوم کامپیوتر و زیست‌شناسی (دانشمندان دیوانه‌ای که پروب‌های الکتریکی را برای این‌که بفهمند مغز چگونه تصاویر را پردازش میکند، در مغز گربه قرار دادند!) الهام گرفته شده است. 66 | 67 | کانولوشن چگونه کار میکند؟ 68 | کانوُلوشِن یا هم‌گشت (Convolution) در ریاضیات یا به طور دقیق‌تر آنالیز تابعی، یک عملگر ریاضی است که بر روی دو تابع f و g به صورت f*g نوشته می‌شود. عمل می‌کند. کانولوشن مشابه تابع هم‌بستگی است. بنابراین این تعریف به صورت انتگرال حاصل‌ضرب دو تابع که یکی از آن‌ها نسبت به محور عمودی مختصات برعکس شده و روی آن یکی می‌لغزد تعریف می‌شود. با این تعریف، کانولوشن یک نوع خاص از تبدیل انتگرالی است. این عملگر از آمار گرفته تا بینایی رایانه‌ای، پردازش تصویر، پردازش سیگنال، مهندسی برق و معادلات دیفرانسیل کاربرد دارد. به جای این‌که کل تصویر را به شکل ماتریسی از اعداد ورودی در نظر بگیریم، با کمک این عملگر و تکنیک‌های دیگر، مفهوم اینکه شی فارغ از مکانش در تصویر همیشه یک مفهوم را می‌رساند، مرحله‌به‌مرحله پیاده‌سازی خواهیم کرد. هدف ساخت مدلی است که احتمال حضور مارمولک در تصویر را تخمین بزند. 69 | 70 | مرحله اول؛ تفکیک تصویر به تعدادی تصویر کوچکتر با هم‌پوشانی 71 | 72 | مشابه ایده پنجره روان، بیایید این بار کل تصویر رو به تصاویر کوچکتری که باهم هم‌پوشانی دارند تقسیم کنیم و به عنوان ورودی‌های متفاوتی در نظر بگیریم. 73 | 74 | تصویر شکسته شده به تصاویر کوچک‌تر هم اندازه که باهم هم‌پوشانی دارند. 75 | تصویر شکسته شده به تصاویر کوچک‌تر هم اندازه که باهم هم‌پوشانی دارند. 76 | در این مثال بخشی مربعی از تصویر اصلی با اندازه ۵۷۶ در ۵۷۶ پیکسل را به ۶۴ کاشی تصویری کوچک‌تر با اندازه برابر که با هم هم‌پوشانی دارند، تقسیم کرده‌ایم. 77 | 78 | مرحله دوم؛ پردازش هر کاشی با یک شبکه عصبی کوچک‌تر 79 | 80 | در بخش قبلی، ما تصویر عدد سه را برای تشخیص به یک شبکه دادیم. در اینجا نیز به همین ترتیب عمل می‌کنیم، اما آن را برای هر کاشی کوچک‌تر در تصویر انجام می‌دهیم. 81 | 82 | مرحله پردازش هر کاشی کوچک‌تر ایجاد شده از تصویر بزرگتر اصلی، به ازای هر کاشی یعنی ۶۴ بار تکرار می‌شود. 83 | مرحله پردازش هر کاشی کوچک‌تر ایجاد شده از تصویر بزرگتر اصلی، به ازای هر کاشی یعنی ۶۴ بار تکرار می‌شود. 84 | با این حال، در این بخش یک تفاوت بزرگ وجود دارد و اون نگهداشتن مقدارهای یادگرفته وزن‌ها در همان شبکه برای تمام کاشی‌ها است. به عبارت دیگر، شبکه با تمام کاشی‌های متفاوت به یک شکل برخورد می‌کند و اگر چیز جالبی در آن کاشی برای یادگیری وجود داشته باشد، شبکه ما آن را بیشتر به یاد می‌سپارد. 85 | 86 | مرحله سوم؛ ذخیره نتایج حاصل از هر کاشی در یک آرایه جدید 87 | 88 | ما نمی‌خواهیم نحوه چیدمان کاشی‌های اصلی را از دست بدهیم. بنابراین نتیجه پردازش هر کاشی را در یک ساختار شطرنجی با همان چیدمان تصویر اصلی ذخیره می‌کنیم. 89 | 90 | در این مرحله تصویر بزرگ اصلی که به کاشی‌های کوچک‌تری تقسیم شده است به شبکه عصبی کوچک داده می‌شود و شبکه با اعمال عملیات کانولوشن، به ازای هر کاشی یک آرایه از اعداد ایجاد می‌کند. 91 | در این مرحله تصویر بزرگ اصلی که به کاشی‌های کوچک‌تری تقسیم شده است به شبکه عصبی کوچک داده می‌شود و شبکه با اعمال عملیات کانولوشن، به ازای هر کاشی یک آرایه از اعداد ایجاد می‌کند. 92 | به بیان دیگر، ما با یک تصویر بزرگ شروع کردیم و به یک آرایه کمی کوچک‌تر رسیدیم که مشخص می‌کند کدام بخش از تصویر اصلی بزرگ ما جالب‌ترین بخش برای یادگیری است. 93 | 94 | مرحله چهارم؛ کاهش نمونه 95 | 96 | نتیجه مرحله قبل، آرایه‌ای است که نمایندگان خوبی برای بخش‌هایی از تصویر اصلی هستند که برای یادگیری جالب هستند. اما این آرایه ها هنوز هم خیلی بزرگ هستند. برای کاهش اندازه آرایه و کاهش نمونه‌ها، از روش بیشینه تجمع (Max Pooling) استفاده می‌کنم. فقط کافی است در هر ناحیه محلی ۲ در ۲ از آرایه‌ها فقط آرایه‌ای را نگه‌داریم که بیشترین مقدار (یا جالب‌ترین ناحیه برای یادگیری) را دارد. 97 | 98 | روش بیشترین تجمیع، از بین آرایه‌ها در یک ساختار محلی بیشترین مقدار را انتخاب می‌کند. 99 | روش بیشترین تجمیع، از بین آرایه‌ها در یک ساختار محلی بیشترین مقدار را انتخاب می‌کند. 100 | در یک تصویر بزرگ چون تعداد کاشی‌ها ممکن است بسیار زیاد باشند و در عین حال باهم هم‌پوشانی هم دارند، ایده این است که از هر چهار کاشی فقط کاشی را در نظر بگیریم که بهترین بخش تصویر برای یادگیری است. با این‌کار اندازه کل مقادیر کاهش یافته و در عین حال مهمترین بخش ها حفظ می شوند. 101 | 102 | مرحله آخر؛ پیش بینی تصویر ورودی 103 | 104 | مدل تا به اینجا، یک تصویر غول پیکر را به آرایه نسبت کوچکی تقلیل داده است. حدس بزنید به چی رسیدیم؟ بله، یک آرایه که فقط دسته‌ای از اعداد است، بنابراین ما می‌توانیم از آن آرایه کوچک به عنوان ورودی یک شبکه عصبی دیگر استفاده کنیم. این شبکه عصبی نهایی تصمیم می‌گیرد که تصویر ورودی چه خواهد بود. برای متمایز‌کردن این شبکه از شبکه کانولوشن (پیچشی)، به اون شبکه عصبی تماما متصل (Fully Connected) می‌گوییم. تصویر زیر تمام پنج مرحله شناسایی تصویر را از ابتدا تا به انتها نشان می‌دهد. 105 | 106 | مدل شبکه عصبی مصنوعی برای تشخیص اشیا از روی تصویر ورودی 107 | مدل شبکه عصبی مصنوعی برای تشخیص اشیا از روی تصویر ورودی 108 | گام‌های بیشتر 109 | 110 | مدل پیشنهادی پردازش تصویر ما از مراحل کانولوشن، بیشینه مقادیر و شبکه عصبی تمام‌متصل تشکیل شده است. اگر بخواهیم یک نمونه برای شناسایی تصاویر پیچیده دنیای واقعی درست کنیم، می‌توانیم این مراحل را به روش‌های مختلف باهم ترکیب کنیم. شما می‌توانید دو، سه یا حتی ده لایه کانولوشن داشته باشید یا از روش تجمیع مقادیر بیشینه در هر‌جایی که نیاز به کاهش داده‌ها دارید، استفاده کنید. 111 | 112 | ایده اولیه این است که با یک تصویر بزرگ اولیه شروع کنیم و پیوسته و مرحله‌به‌مرحله مفاهیم بیشتری را یادبگیریم. هرچه گام‌های کانولوشن بیشتری داشته باشیم، شبکه ویژگی‌های پیچیده‌تری از تصویر را یاد خواهد گرفت. برای مثال اولین مرحله کانولوشن ممکن است لبه‌های تیز را تشخیص دهد، گام دوم اشکال بسته را با استفاده از دانش خود از اشکال بسته و نهایتا در آخرین مرحله کل مارمولک را با استفاده از دانش اشکال بسته تشخیص دهد. در تصویر زیر یک شبکه عصبی عمیق برای تشیخص تصویر مشابه آنچه در مقالات علمی خواهید یافت را مشاهده میکنید. 113 | 114 | مدل YOLO برای تشخیص بلادرنگ اشیا در تصویر با دقت بالا 115 | مدل YOLO برای تشخیص بلادرنگ اشیا در تصویر با دقت بالا 116 | در این نمونه، مدل یک تصویر ۴۴۸ در ۴۴۸ پیکسل را دریافت می‌کند. سپس چهار بار کانولوشن و تجمیع انجام میدهد. اعداد یافته شده نهایی به یک شبکه عصبی تماما‌متصل با دو لایه ورودی داده می شود. در آخر شبکه می تواند کلاس تصویر را از بین ۱۰۰۰ کلاس انتخاب کند. حتی این مدل می‌تواند چند شی را در تصویر شناسایی کرده و محل دقیق آنها رو هم علامت‌گذاری کند. 117 | 118 | معماری مناسب برای یک شبکه 119 | 120 | شاید برای شما سوال شده باشد که چطور می‌توانیم این مراحل را با هم ترکیب کنیم تا یک مدل خوب داشته باشیم؟ اگر بخواهیم صادقانه به این سوال پاسخ دهیم، فقط انجام چندین و چند آزمایش می تواند خوب بودن یک مدل از شبکه را مشخص کند. شما ممکن است قبل از رسیدن به یک معماری خوب از شبکه، صد شبکه با پارامترهای مختلف را آموزش دهید تا به یک نتیجه دلخواه برسید. برای اینکه نتایج قابل مقایسه باشند نیز روش‌های مختلف کمی وجود دارد که با توجه به کاربرد شبکه انتخاب می‌شوند. خلاصه بخش زیادی از یادگیری عمیق و یادگیری ماشین سعی و خطاست! 121 | 122 | تشخیص هواپیما در تصاویر هوایی با یادگیری عمیق 123 | حالا معلومات ما به اندازه کافی برای نوشتن برنامه‌ای که تصمیم بگیرد یک تصویر هواپیما است یا خیر زیاد شده است. در دنیای دیجیتال امروز تصاویر هوایی کاربردهای زیادی در حوزه‌های مختلف از جمله کشاورزی، منابع طبیعی، انرژی، مدیریت شهری و ترافیک، مدیریت بحران و حتی مالی پیدا کرده است. شرکت‌های مختلفی با استفاده از ماهواره‌های کوچک، بالون یا پهپادها سعی در جمع آوری هرچه بیشتر تصاویر هوایی و ارائه خدمات مختلف در این بستر دارند. در این سیل عظیم تصاویری که روزانه جمع می شوند، امکان بررسی دستی توسط اوپراتور و تصمیم گیری عملا غیرممکن است. بنابراین نیاز مبرمی به هوش مصنوعی، یادگیری ماشین و بینایی کامپیوتر برای کمک به خودکار کردن روند تجزیه و تحلیل حس می‌شود. 124 | 125 | ما هم مثل همیشه برای شروع نیاز به تصاویری برای خلق ماشین خودمان داریم. برای این منظور از این مجموعه داده که از تصاویر متن‌باز ماهواره‌ای کالیفرنیا تهیه شده‌اند، استفاده می کنیم. این مجموعه داده شامل ۸۰۰۰ عکس هوایی از هواپیماها است که تصاویر تقریبا یک هواپیما در وسط تصویر است که در بیشتر آن‌ها باله، دم و نوک هواپیما قابل مشاهده هستند. بنابراین نمونه های مختلفی از هواپیما با اندازه‌ها، جهت قرارگیری و شرایط مختلف محیطی در دسترس هستند. تصویر زیر نمونه‌ای از هواپیماها در مجموعه را نشان میدهد. 126 | 127 | نمونه تصاویر هواپیما با اندازه‌ها، جهت قرارگیری و شرایط مختلف محیطی که از تصاویر هوایی استخراج شده‌اند. 128 | نمونه تصاویر هواپیما با اندازه‌ها، جهت قرارگیری و شرایط مختلف محیطی که از تصاویر هوایی استخراج شده‌اند. 129 | تصاویر دیگر موجود در مجموعه شامل اشیا دیگر در تصاویر هوایی هستند که جمعا ۲۴۰۰۰ تصویر هستند. یک سوم از نمونه ها پوشش‌های طبیعی مختلف روی زمین مثل آب، درختان، زمین‌خالی، ساختمان و غیره هستند که هیچ هواپیمایی را شامل نمی‌شوند. یک سوم دیگر تنها جزئی از هواپیما را نشان میدهند که برای یادگیری تمام مفهوم هواپیما کافی نیستند. یک سوم نهایی اما اشیا جالبی هستند که براق و شبیه هواپیما هستند و ممکن است مدل را دچار اشتباه کند. این تصاویر توسط مدل‌های هوش مصنوعی قبلا علامت‌گذاری شدند اما هواپیما نیستند. 130 | 131 | نمونه تصاویر منتخب استخراج شده از تصاویر هوایی که هواپیما در آن‌ها حضور ندارد و اشیا دیگر مثل عوارض طبیعی زمین، ساختمان، آب یا تنها بخشی از هواپیما یا اشیایی شبیه هواپیما در آن قابل مشاهده است. 132 | نمونه تصاویر منتخب استخراج شده از تصاویر هوایی که هواپیما در آن‌ها حضور ندارد و اشیا دیگر مثل عوارض طبیعی زمین، ساختمان، آب یا تنها بخشی از هواپیما یا اشیایی شبیه هواپیما در آن قابل مشاهده است. 133 | این مجموعه داده برای رسیدن به هدف این مطلب که یادگیری و در عین حال ایجاد یک ماشین خودکار شناسایی تصاویر است کفایت می‌کند. اما این تعداد محدود تصاویر آن هم با وضوح کم هنوز برای برنامه‌های تجاری واقعی نامناسب است. اگر شما به برنامه‌ای با سطح عملکرد گوگل فکر می‌کنید، نیاز به میلیون ها تصویر بزرگ با کیفیت دارید. در یادگیری ماشین برای ایجاد یک الگوریتم شناسایی خوب همیشه داشتن اطلاعات زیاد بسیار مهم است. احتمالا الان می تونید حدس بزنید چرا گوگل از در اختیار قراردادن یک فضای نامحدود در گوگل فوتوز خوشحال است! 134 | 135 | در اینجا ما برای ساخت طبقه‌بند (Classifier) خود از تنسورفلو و امکانات یادگیری عمیق در آن استفاده می کنیم. در نسخه‌های جدید ایجاد یک شبکه عصبی عمیق کانولوشن به آسانی نوشتن چند خط کد و تعریف لایه‌های مختلف شبکه است. در کنار آن نیز فراموش نکنید نیاز دارید تا این داده‌ها را دریافت کنید و برای آموزش آماده کنید. برای دریافت و آماده سازی داده‌ها از دستورات زیر استفاده می‌کنیم: 136 | 137 | 1 138 | 2 139 | 3 140 | 4 141 | 5 142 | 6 143 | pip install kaggle 144 | mkdir -p ~/.kaggle 145 | cp kaggle.json ~/.kaggle/ 146 | chmod 600 ~/.kaggle/kaggle.json 147 | kaggle datasets download -d rhammell/planesnet 148 | unzip planesnet.zip 149 | تصاویر دریافت شده را با استفاده از فهرست موجود در کنار داده‌ها، به شکل زیر در برنامه فراخوانی می‌کنیم: 150 | 151 | 1 152 | 2 153 | 3 154 | 4 155 | 5 156 | 6 157 | 7 158 | 8 159 | 9 160 | 10 161 | 11 162 | 12 163 | 13 164 | 14 165 | def LoadDir(dirname): 166 | imgs = [np.zeros([20,20,3])] 167 | labels = [0] 168 | for imgname in os.listdir(dirname): 169 | if(imgname[0] == '1'): 170 | labels.append(1) 171 | else: 172 | labels.append(0) 173 | if os.path.isfile(os.path.join(dirname, imgname)): 174 | img = Image.open(os.path.join(dirname, imgname)) 175 | img = np.array(img) 176 | imgs.append(img) 177 | return np.array(imgs),np.array(labels) 178 | imgs, labels = LoadDir(r'planesnet/planesnet/') 179 | حال باید داده‌های آموزشی و آزمایشی را از هم تفکیک کنیم. در همین مرحله نیز می‌توانیم داده‌های مشابه برای یادگیری بهتر ایجاد کنیم: 180 | 181 | 1 182 | 2 183 | 3 184 | 4 185 | 5 186 | 6 187 | 7 188 | 8 189 | 9 190 | 10 191 | x_train, x_temp, y_train, y_temp = train_test_split(imgs, labels, test_size = 0.20, random_state = 42, shuffle = True) 192 | x_valid, x_test, y_valid, y_test = train_test_split(x_temp, y_temp, test_size = 0.50, random_state = 42, shuffle = True) 193 | x_train1 = np.rot90(x_train, k = 1, axes = (1, 2)) #Generate new samples 194 | x_train2 = np.rot90(x_train, k = 2, axes = (1, 2)) 195 | x_train3 = np.rot90(x_train, k = 3, axes = (1, 2)) 196 | x_train = np.append(x_train, x_train1, axis = 0) 197 | x_train = np.append(x_train, x_train2, axis = 0) 198 | x_train = np.append(x_train, x_train3, axis = 0) 199 | y_train = np.append(y_train, y_train) 200 | y_train = np.append(y_train, y_train) 201 | در ادامه مدل را تعریف و آموزش شبکه عصبی کانولوشن را شروع می‌کنیم: 202 | 203 | 1 204 | 2 205 | 3 206 | 4 207 | 5 208 | 6 209 | 7 210 | 8 211 | 9 212 | 10 213 | 11 214 | 12 215 | 13 216 | 14 217 | 15 218 | 16 219 | 17 220 | 18 221 | 19 222 | 20 223 | 21 224 | 22 225 | model = Sequential() 226 | def swish(x): 227 | return (K.sigmoid(x) * x) 228 | get_custom_objects().update({'swish': Activation(swish)}) 229 | model.add(Conv2D(16, 2, padding = 'valid', input_shape = (20,20,3))) 230 | model.add(BatchNormalization()) 231 | model.add(Activation('tanh')) 232 | model.add(MaxPooling2D((2,2))) 233 | model.add(Conv2D(32, 3, padding = 'valid')) 234 | model.add(BatchNormalization()) 235 | model.add(Activation('swish')) 236 | model.add(Dropout(0.2)) 237 | model.add(MaxPooling2D((2,2))) 238 | model.add(Conv2D(64, 2, kernel_initializer = 'random_uniform', padding = 'valid')) #64 2 239 | model.add(BatchNormalization()) 240 | model.add(Activation('swish')) 241 | model.add(Dropout(0.2)) 242 | model.add(Flatten()) 243 | model.add(Dense(1, activation = 'sigmoid')) 244 | opt = keras.optimizers.SGD(lr = 0.01, momentum = 0.1, decay = 0.00005, nesterov = True) 245 | model.compile(optimizer = opt, loss = 'binary_crossentropy', metrics = ['binary_accuracy']) 246 | log = model.fit(x_train, y_train, shuffle = True, validation_data = (x_valid, y_valid), epochs = 200) 247 | اگر برای اجرای این کد از یک کارت گرافیک خوب و حافظه کافی استفاده می‌کنید، به زمانی کمتر از یک ساعت برای آموزش و تنظیم وزن های شبکه نیاز دارید. اگر از یک پردازنده معمولی استفاده می‌کنید، ممکن است این فرآیند چند ساعت زمان نیاز داشته باشد. با آموزش هرچه بیشتر مدل دقت آن نیز افزایش می‌یابد. در پیاده‌سازی که انجام دادم، بعد از اولین تکرار (Epoch) دقت مدل ۸۵.۲۸ درصد بود. تنها بعد از ۱۰ تکرار این دقت به ۹۷ درصد رسید. بعد از گذشت ۵۰ تکرار، دقت مدل آموزش داده شده به ۹۸.۵۶ درصد رسید و تغییری نکرد. شما می تونید از روش‌های مختلف مثل چرخش تصاویر، تغییر اندازه، تغییر رنگ یا غیره داده‌های بیشتری مشابه داده‌های ورودی تولید کنید یا معماری مدل را تغییر دهید تا به دقت بیشتری برسید. همچنین اگر علاقمندید می تونید با روش پنجره روان با اندازه های مختلف که در بخش اول توضیح دادیم، از یک تصویر هوایی، تصاویر کوچکتری را انتخاب کنید تا بتونید محل دقیق هواپیما در یک عکس بزرگ تشخیص دهید. تبریک میگم، حالا ما یک مدل هوش مصنوعی داریم که در تصاویر هوایی هواپیما را تشخیص می‌دهد! 248 | 249 | آزمایش شبکه با یک تصویر ورودی 250 | حال با داشتن یک تصویر ورودی یا بخشی از تصویر ماهواره‌ای، می‌تونیم مدل آموزش داده شده را بازیابی کرده و از آن برای تشخیص هوایپما در تصویر استفاده کنیم. 251 | 252 | 1 253 | 2 254 | 3 255 | 4 256 | y_pred = model.predict(x_test) 257 | y_pred[y_pred > 0.5] = 1 258 | y_pred[y_pred < 0.5] = 0 259 | y_pred = np.asarray(y_pred, dtype=bool) 260 | اما برای اینکه واقعا ببینیم شبکه ما چقدر موثر است، باید آن را با تصاویر زیادی آزمایش کنیم. از آنجایی‌که مجموعه داده‌ای که از آن استفاده کرده‌ایم، شامل تعدادی تصاویر است که از قبل وجود یا عدم وجود هوایپما در آن مشخص شده است، از همین تصاویر استفاده می‌کنم. یعنی هر تصویر را به مدل آموزش داده شده می‌دهیم و نتیجه پیش‌بینی شبکه را با مقدار اصلی مقایسه می‌کنیم. میانگین نمونه‌های درست، دقت را مشخص می‌کند. همان‌طور که گفتیم دقت در اینجا نزدیک به ۹۹ درصد است. اما واقعا این عدد خوب است؟ 261 | 262 | دقت ۹۹ درصد چقدر دقیق است؟ 263 | ادعای شبکه ما این است که دقت بالایی دارد. اما این عدد در ظاهر به سادگی دقت را بیان می‌کند، اما وقتی به جزئیات فکر کنیم، دشوارتر از چیزی است که تصور می‌کنیم. به طور مثال چه اتفاقی می‌افتد اگر ۹۹ درصد از تصاویر آموزشی ما هواپیما و بقیه هواپیما نباشند؟ در این حالت تنها نیاز داریم تا برنامه همیشه بگوید ورودی یک هواپیما است و دقت هم ۹۹ درصد است! ولی خب اینکار ۱۰۰ درصد بی‌فایده است. 264 | 265 | ما باید تحلیل دقیق‌تری از یک دقت کلی داشته باشیم. برای قضاوت درباره اینکه یک سیستم طبقه‌بند واقعا چقدر خوب است، باید در مورد اینکه چطور خوب نبوده است نیز صحبت کنیم. نه فقط درصد زمانی که خوب عمل نکرده است. پس بیایید به جای فکر کردن در مورد اینکه پیش‌بینی ما «درست» یا «غلط» بوده است، آن را به چهار دسته مجزا تقسیم کنیم. 266 | 267 | اول، هواپیماهایی که شبکه به درستی به عنوان هواپیما شناخته است که آن را مثبت صحیح (True Positive) می‌نامیم. دوم، همان تصاویری که هواپیما نبودند و به درستی شناسایی شدند که به آن ها منفی صحیح (True Negative) می‌گوییم. سوم، تصاویری که مدل فکر میکرد هواپیما هستند ولی این‌طور نبودند که مثبت کاذب (False Positive) می‌گوییم. و چهارم، تصاویری از هواپیما که شبکه نتوانسته است آن‌ها را هواپیما شناسایی کند که منفی کاذب (False Negative) گوییم. 268 | 269 | در جدول زیر با اعتبارسنجی مدل بر اساس داده‌های آزمایشی دقت با جزئیات بیشتری بر اساس معیارهای مختلف که این چهار دسته را در نظر میگیرند، آمده است: 270 | 271 | 272 | نمودارهای زیر نیز تغییرات خطای مدل در هر بار تکرار در آموزش شبکه و دقت نمونه های آموزشی و آزمایشی را نشان میدهد. 273 | 274 | دقت شبکه عصبی عمیق برای شناسایی تصاویر هواپیما در فرآیند آموزش بر اساس نمونه‌های آموزشی و آزمایشی به همراه خطا در هر تکرار 275 | دقت شبکه عصبی عمیق برای شناسایی تصاویر هواپیما در فرآیند آموزش بر اساس نمونه‌های آموزشی و آزمایشی به همراه خطا در هر تکرار 276 | شاید شما سوال بپرسید چرا ما نتایج خود را این‌گونه تجزیه و تحلیل میکنیم؟ پاسخ این است که همه اشتباهات با هم برابر نیستند. تصور کنید ما می‌خواهیم یک برنامه برای تشخیص سرطان با استفاده از تصاویر ام‌آر‌آی بنویسیم. اگر برنامه سرطان را تشخیص دهد، ترجیح می‌دهیم تا مثبت کاذب باشند تا منفی کاذب؛ یعنی اگر منفی کاذب داشته باشیم برنامه به افراد زیادی می‌گوید سرطان ندارند اما آن‌ها سرطان دارند. بنابراین ما به جای محاسبه یک دقت کلی از معیار دقت و بازیابی یا امتیاز اف یک استفاده می‌کنیم که موارد گفته شده را درنظر بگیرد. 277 | 278 | پیاده‌سازی کامل مدل و منابع مرتبط با این مطلب به صورت کامل از طریق گیت‌هاب و مطلب قبلی از اینجا در دسترس است. همچنین اگر علاقمند به موضوعات هوش مصنوعی، یادگیری ماشین و بینایی کامپیوتر هستید می‌تونید من رو در توییتر دنبال کنید. خوشحال میشم اگر مطلب رو پسندید با بقیه به اشتراک بذارید و 🧡 کنید. 279 | 280 | ویدیو نمایشی پروژه خودروی خودران برای نظارت بر رفتار راننده برای جلوگیری از تصادفات ناشی از اشتباهات راننده 281 | ویدیو نمایشی پروژه خودروی خودران برای نظارت بر رفتار راننده برای جلوگیری از تصادفات ناشی از اشتباهات راننده 282 | در نوشتن این متن از ترجمه کلمات تخصصی علوم کامپیوتر و هوش مصنوعی در فارسی استفاده شده است که از دیکشنری متن‌باز تخصصی انگلیسی‌-‌فارسی علوم کامپیوتر انتخاب شده‌اند. شما هم می‌تونید از اینجا با مشارکت در تکمیل یا اصلاح فهرست واژگان رشته تخصصی خود سهمی در گسترش علم داشته باشید. 283 | این ماجراجویی تموم شد. حالا نوبت شماست که شبکه عصبی خودتون رو برای شناخت اشیا در تصاویر طراحی کنید و تجربیاتتون رو به اشتراک بذارید. به نظر شما ایجاد یک برنامه برای شناخت همزمان چندین موجودیت در تصویر چه چالش هایی به همراه داره؟ 284 | -------------------------------------------------------------------------------- /introduction-to-deep-learning-with-keras-workshop/03.Introduction to Deep Learning with Keras Workshop_cat_vs_dog.ipynb: -------------------------------------------------------------------------------- 1 | {"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"03.Introduction to Deep Learning with Keras Workshop_cat_vs_dog.ipynb","version":"0.3.2","provenance":[],"collapsed_sections":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"accelerator":"GPU"},"cells":[{"metadata":{"id":"okFF46GObvJf","colab_type":"text"},"cell_type":"markdown","source":["#**Introduction to Deep Learning with Keras Workshop**\n","*Tutorial Session of the International Conference on Contemporary Issues In Data Science (CiDaS)* - 5, 6 May 2019\n","\n","Lecturer: Hadi Abdi Khojasteh\n","\n","hkhojasteh [at] iasbs.ac.ir
\n","https://github.com/hkhojasteh/Personal-Blog"]},{"metadata":{"id":"YqyuEGmuJpB0","colab_type":"text"},"cell_type":"markdown","source":["#Classification with Convolutionl Neural Networks - CNN"]},{"metadata":{"id":"7kN-RRY7Jv_s","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":34},"outputId":"a7c51736-ece8-4bd5-cfe6-d659b78b2317","executionInfo":{"status":"ok","timestamp":1551760831246,"user_tz":-210,"elapsed":1834,"user":{"displayName":"Hadi Abdi Khojasteh","photoUrl":"https://lh3.googleusercontent.com/-rJo5BXlqcyI/AAAAAAAAAAI/AAAAAAAAADg/jS3hH6xCFrw/s64/photo.jpg","userId":"07595703282416442298"}}},"cell_type":"code","source":["import keras"],"execution_count":1,"outputs":[{"output_type":"stream","text":["Using TensorFlow backend.\n"],"name":"stderr"}]},{"metadata":{"id":"DEshESjiJ8uc","colab_type":"text"},"cell_type":"markdown","source":["##Dataset\n","\n","![cats_vs_dogs_samples](https://s3.amazonaws.com/book.keras.io/img/ch5/cats_vs_dogs_samples.jpg)\n","\n","Unsurprisingly, the cats vs. dogs Kaggle competition in 2013 was won by entrants who used convnets. The best entries could achieve up to \n","95% accuracy. In our own example, we will get fairly close to this accuracy (in the next section), even though we will be training our \n","models on less than 10% of the data that was available to the competitors.\n","This original dataset contains 25,000 images of dogs and cats (12,500 from each class) and is 543MB large (compressed). After downloading \n","and uncompressing it, we will create a new dataset containing three subsets: a training set with 1000 samples of each class, a validation \n","set with 500 samples of each class, and finally a test set with 500 samples of each class.\n","\n","Here are a few lines of code to do this:"]},{"metadata":{"id":"_nUpNggQKF_K","colab_type":"code","colab":{}},"cell_type":"code","source":["import os, shutil"],"execution_count":0,"outputs":[]},{"metadata":{"id":"rO7_tlPvMLQe","colab_type":"text"},"cell_type":"markdown","source":["##Check imags\n","Accuracy is good enough."]},{"metadata":{"id":"tGejpQX-JRXx","colab_type":"code","outputId":"0256db2e-cbab-4ff9-9a5b-6e8f5db0a59c","colab":{}},"cell_type":"code","source":["train_cats_dir"],"execution_count":0,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'D:/dataset/catDog/catVsdog\\\\train\\\\cats'"]},"metadata":{"tags":[]},"execution_count":4}]},{"metadata":{"scrolled":true,"id":"IbzPwbglJRX4","colab_type":"code","outputId":"583b2929-2259-40e2-f9a6-e0b191b43478","colab":{}},"cell_type":"code","source":["print('total training cat images:', len(os.listdir(train_cats_dir)))"],"execution_count":0,"outputs":[{"output_type":"stream","text":["total training cat images: 1000\n"],"name":"stdout"}]},{"metadata":{"id":"M85lRbWuJRX8","colab_type":"code","outputId":"4cd4ba6a-1f1e-4af0-9918-6f1e8db6e911","colab":{}},"cell_type":"code","source":["print('total training dog images:', len(os.listdir(train_dogs_dir)))"],"execution_count":0,"outputs":[{"output_type":"stream","text":["total training dog images: 1000\n"],"name":"stdout"}]},{"metadata":{"id":"HOuRXe27JRYB","colab_type":"code","outputId":"99de1e20-aca5-47af-fe6e-3654c35bbc28","colab":{}},"cell_type":"code","source":["print('total validation cat images:', len(os.listdir(validation_cats_dir)))"],"execution_count":0,"outputs":[{"output_type":"stream","text":["total validation cat images: 500\n"],"name":"stdout"}]},{"metadata":{"id":"P1tTuA3dJRYF","colab_type":"code","outputId":"9de697c5-bbd8-4280-fe9b-21184173b468","colab":{}},"cell_type":"code","source":["print('total validation dog images:', len(os.listdir(validation_dogs_dir)))"],"execution_count":0,"outputs":[{"output_type":"stream","text":["total validation dog images: 500\n"],"name":"stdout"}]},{"metadata":{"id":"aY04bvBfJRYL","colab_type":"code","outputId":"3ff5cff8-b897-4b82-e8c3-bbbc8b612aef","colab":{}},"cell_type":"code","source":["print('total test cat images:', len(os.listdir(test_cats_dir)))"],"execution_count":0,"outputs":[{"output_type":"stream","text":["total test cat images: 500\n"],"name":"stdout"}]},{"metadata":{"id":"gLYELkpZJRYP","colab_type":"code","outputId":"f83abb8a-b55b-4a25-f970-6c23af67baf8","colab":{}},"cell_type":"code","source":["print('total test dog images:', len(os.listdir(test_dogs_dir)))"],"execution_count":0,"outputs":[{"output_type":"stream","text":["total test dog images: 500\n"],"name":"stdout"}]},{"metadata":{"id":"rDKoCsrWMpMU","colab_type":"text"},"cell_type":"markdown","source":["##model architecture\n","Since we are attacking a binary classification problem, we are ending the network with a single unit (a Dense layer of size 1) and a sigmoid activation. This unit will encode the probability that the network is looking at one class or the other."]},{"metadata":{"id":"2kHGOsUbMrTL","colab_type":"code","colab":{}},"cell_type":"code","source":["model.add(layers.MaxPooling2D((2, 2)))"],"execution_count":0,"outputs":[]},{"metadata":{"id":"yJibHBjCMuni","colab_type":"text"},"cell_type":"markdown","source":["Let's take a look at how the dimensions of the feature maps change with every successive layer:"]},{"metadata":{"id":"SKBNDrVhMrz2","colab_type":"code","colab":{}},"cell_type":"code","source":["model.summary()"],"execution_count":0,"outputs":[]},{"metadata":{"id":"sohQFhskMxr8","colab_type":"text"},"cell_type":"markdown","source":["For our compilation step, we'll go with the `RMSprop` optimizer as usual. Since we ended our network with a single sigmoid unit, we will \n","use binary crossentropy as our loss (as a reminder, check out the table in Chapter 4, section 5 for a cheatsheet on what loss function to \n","use in various situations)."]},{"metadata":{"id":"o47ZmbtdMym7","colab_type":"code","colab":{}},"cell_type":"code","source":["from keras import optimizers\n","\n","model.compile(loss='binary_crossentropy',\n"," optimizer=optimizers.RMSprop(lr=1e-4),\n"," metrics=['acc'])"],"execution_count":0,"outputs":[]},{"metadata":{"id":"xYug9kXQM0KZ","colab_type":"text"},"cell_type":"markdown","source":["##Data preprocessing\n","\n","* Read the picture files.\n","* Decode the JPEG content to RGB grids of pixels.\n","* Convert these into floating point tensors.\n","* Rescale the pixel values (between 0 and 255) to the [0, 1] interval (as you know, neural networks prefer to deal with small input values).\n","\n","It may seem a bit daunting, but thankfully Keras has utilities to take care of these steps automatically. Keras has a module with image \n","processing helper tools, located at `keras.preprocessing.image`. In particular, it contains the class `ImageDataGenerator` which allows to \n","quickly set up Python generators that can automatically turn image files on disk into batches of pre-processed tensors. This is what we \n","will use here.\n","\n","`https://keras.io/preprocessing/image/`"]},{"metadata":{"id":"iPrYbwI5M5YB","colab_type":"code","colab":{}},"cell_type":"code","source":["from keras.preprocessing.image import ImageDataGenerator\n","\n","# All images will be rescaled by 1./255\n","train_datagen = ImageDataGenerator(rescale=1./255)\n","test_datagen = ImageDataGenerator(rescale=1./255)\n","\n","train_generator = train_datagen.flow_from_directory(\n"," # This is the target directory\n"," train_dir,\n"," # All images will be resized to 150x150\n"," target_size=(150, 150),\n"," batch_size=20,\n"," # Since we use binary_crossentropy loss, we need binary labels\n"," class_mode='binary')\n","\n","validation_generator = test_datagen.flow_from_directory(\n"," validation_dir,\n"," target_size=(150, 150),\n"," batch_size=20,\n"," class_mode='binary')"],"execution_count":0,"outputs":[]},{"metadata":{"id":"yqcdgNhsM72B","colab_type":"text"},"cell_type":"markdown","source":["Let's take a look at the output of one of these generators: it yields batches of 150x150 RGB images (shape `(20, 150, 150, 3)`) and binary \n","labels (shape `(20,)`). 20 is the number of samples in each batch (the batch size). Note that the generator yields these batches \n","indefinitely: it just loops endlessly over the images present in the target folder. For this reason, we need to `break` the iteration loop \n","at some point."]},{"metadata":{"id":"thXG906zM9RR","colab_type":"code","colab":{}},"cell_type":"code","source":["for data_batch, labels_batch in train_generator:\n"," print('data batch shape:', data_batch.shape)\n"," print('labels batch shape:', labels_batch.shape)\n"," break"],"execution_count":0,"outputs":[]},{"metadata":{"id":"hmCrUI1rM-qi","colab_type":"text"},"cell_type":"markdown","source":["Let's fit our model to the data using the generator. We do it using the `fit_generator` method, the equivalent of `fit` for data generators \n","like ours. It expects as first argument a Python generator that will yield batches of inputs and targets indefinitely, like ours does. \n","Because the data is being generated endlessly, the generator needs to know example how many samples to draw from the generator before \n","declaring an epoch over. This is the role of the `steps_per_epoch` argument: after having drawn `steps_per_epoch` batches from the \n","generator, i.e. after having run for `steps_per_epoch` gradient descent steps, the fitting process will go to the next epoch. In our case, \n","batches are 20-sample large, so it will take 100 batches until we see our target of 2000 samples.\n","\n","When using `fit_generator`, one may pass a `validation_data` argument, much like with the `fit` method. Importantly, this argument is \n","allowed to be a data generator itself, but it could be a tuple of Numpy arrays as well. If you pass a generator as `validation_data`, then \n","this generator is expected to yield batches of validation data endlessly, and thus you should also specify the `validation_steps` argument, \n","which tells the process how many batches to draw from the validation generator for evaluation."]},{"metadata":{"id":"w5R9z4ZNM_9R","colab_type":"code","colab":{}},"cell_type":"code","source":["history = model.fit_generator(\n"," train_generator,\n"," steps_per_epoch=100,\n"," epochs=30,\n"," validation_data=validation_generator,\n"," validation_steps=50)"],"execution_count":0,"outputs":[]},{"metadata":{"id":"8q97WYfqNB24","colab_type":"text"},"cell_type":"markdown","source":["Let's plot the loss and accuracy of the model over the training and validation data during training:"]},{"metadata":{"id":"RvJGuXWsNCdR","colab_type":"code","colab":{}},"cell_type":"code","source":["import matplotlib.pyplot as plt\n","%matplotlib inline\n","acc = history.history['acc']\n","val_acc = history.history['val_acc']\n","loss = history.history['loss']\n","val_loss = history.history['val_loss']\n","\n","epochs = range(len(acc))\n","\n","plt.plot(epochs, acc, 'bo', label='Training acc')\n","plt.plot(epochs, val_acc, 'b', label='Validation acc')\n","plt.title('Training and validation accuracy')\n","plt.legend()\n","\n","plt.figure()\n","\n","plt.plot(epochs, loss, 'bo', label='Training loss')\n","plt.plot(epochs, val_loss, 'b', label='Validation loss')\n","plt.title('Training and validation loss')\n","plt.legend()\n","\n","plt.show()"],"execution_count":0,"outputs":[]},{"metadata":{"id":"DjYJzVvANFVB","colab_type":"text"},"cell_type":"markdown","source":["These plots are characteristic of overfitting. Our training accuracy increases linearly over time, until it reaches nearly 100%, while our \n","validation accuracy stalls at 70-72%. Our validation loss reaches its minimum after only five epochs then stalls, while the training loss \n","keeps decreasing linearly until it reaches nearly 0.\n","\n","Because we only have relatively few training samples (2000), overfitting is going to be our number one concern.\n","Let's train our network using data augmentation and dropout:"]},{"metadata":{"id":"h-BeqQ6QNG0T","colab_type":"text"},"cell_type":"markdown","source":["##Dropout"]},{"metadata":{"id":"3ssUcyngNEvR","colab_type":"code","colab":{}},"cell_type":"code","source":["model = models.Sequential()\n","model.add(layers.Conv2D(32, (3, 3), activation='relu',\n"," input_shape=(150, 150, 3)))\n","model.add(layers.MaxPooling2D((2, 2)))\n","model.add(layers.Conv2D(64, (3, 3), activation='relu'))\n","model.add(layers.MaxPooling2D((2, 2)))\n","model.add(layers.Conv2D(128, (3, 3), activation='relu'))\n","model.add(layers.MaxPooling2D((2, 2)))\n","model.add(layers.Conv2D(128, (3, 3), activation='relu'))\n","model.add(layers.MaxPooling2D((2, 2)))\n","model.add(layers.Flatten())\n","model.add(layers.Dropout(0.5))\n","model.add(layers.Dense(512, activation='relu'))\n","model.add(layers.Dense(1, activation='sigmoid'))\n","\n","model.compile(loss='binary_crossentropy',\n"," optimizer=optimizers.RMSprop(lr=1e-4),\n"," metrics=['acc'])\n","\n","history = model.fit_generator(\n"," train_generator,\n"," steps_per_epoch=100,\n"," epochs=100,\n"," validation_data=validation_generator,\n"," validation_steps=50)"],"execution_count":0,"outputs":[]},{"metadata":{"id":"-RTrSSIzNLe9","colab_type":"text"},"cell_type":"markdown","source":["Let's plot our results again:"]},{"metadata":{"id":"vBWqkEoTNMfj","colab_type":"code","colab":{}},"cell_type":"code","source":["acc = history.history['acc']\n","val_acc = history.history['val_acc']\n","loss = history.history['loss']\n","val_loss = history.history['val_loss']\n","\n","epochs = range(len(acc))\n","\n","plt.plot(epochs, acc, 'bo', label='Training acc')\n","plt.plot(epochs, val_acc, 'b', label='Validation acc')\n","plt.title('Training and validation accuracy')\n","plt.legend()\n","\n","plt.figure()\n","\n","plt.plot(epochs, loss, 'bo', label='Training loss')\n","plt.plot(epochs, val_loss, 'b', label='Validation loss')\n","plt.title('Training and validation loss')\n","plt.legend()\n","\n","plt.show()"],"execution_count":0,"outputs":[]},{"metadata":{"id":"J0VYg-NGNONR","colab_type":"code","colab":{}},"cell_type":"code","source":["model.save('cats_and_dogs_small_1.h5')"],"execution_count":0,"outputs":[]}]} -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Personal Blog 2 | [Hadi Abdi Khojasteh](http://hadiabdikhojasteh.ir) personal blog contents that hosted [here](https://virgool.io/@hadiakhojasteh/). 3 | 4 | [![HitCount](http://hits.dwyl.io/hkhojasteh/Personal-Blog.svg)](https://github.com/hkhojasteh/Personal-Blog) 5 | 6 | ## Contents 7 |
8 | 9 |

How to break a Golestan CAPTCHA system with machine learning

10 |

چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟

11 | https://virgool.io/@hadiakhojasteh/how-to-break-a-golestan-captcha-system-with-machine-learning-kukzjnwwsqdx
12 |
13 |
14 |
15 | 16 |

How to build an intelligent car with image processing

17 |

هک خودرو؛ چطوری با پردازش تصویر خودرومونو هوشمند کنیم؟

18 | https://virgool.io/@hadiakhojasteh/how-to-build-an-intelligent-car-with-image-processing-rkgz4q8v37xg
19 |
20 |
21 |
22 | 23 |

How to detect airplanes in satellite imagery with convolutional neural networks

24 | چطوری با بینایی کامپیوتر هواپیماها رو در تصویر هوایی پیدا کنیم؟

25 | https://vrgl.ir/2XOI1 26 |
27 | 28 | ## Copyright 29 | Copyright (c) 2018-2021 by Hadi Abdi Khojasteh 30 | 31 | ## License 32 | GNU General Public License v3.0 33 | --------------------------------------------------------------------------------