File indexing completed on 2024-05-12 05:09:21
0001 /*************************************************************************** 0002 Copyright (C) 2007-2009 Sebastian Held <sebastian.held@gmx.de> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * based on BaToo: http://www.vs.inf.ethz.ch/res/show.html?what=barcode * 0008 * * 0009 * This program is free software; you can redistribute it and/or * 0010 * modify it under the terms of the GNU General Public License as * 0011 * published by the Free Software Foundation; either version 2 of * 0012 * the License or (at your option) version 3 or any later version * 0013 * accepted by the membership of KDE e.V. (or its successor approved * 0014 * by the membership of KDE e.V.), which shall act as a proxy * 0015 * defined in Section 14 of version 3 of the license. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0024 * * 0025 ***************************************************************************/ 0026 0027 // includes code from https://www.linuxtv.org/downloads/v4l-dvb-apis-old/capture-example.html 0028 0029 #include "barcode.h" 0030 0031 #include <QImage> 0032 #include <QMutex> 0033 #include <QDebug> 0034 0035 #include <stdlib.h> 0036 0037 using barcodeRecognition::barcodeRecognitionThread; 0038 using barcodeRecognition::Barcode_EAN13; 0039 using barcodeRecognition::Decoder_EAN13; 0040 using barcodeRecognition::MatchMakerResult; 0041 0042 barcodeRecognitionThread::barcodeRecognitionThread() 0043 { 0044 m_stop = false; 0045 m_barcode_v4l = new barcode_v4l(); 0046 } 0047 barcodeRecognitionThread::~barcodeRecognitionThread() 0048 { 0049 delete m_barcode_v4l; 0050 } 0051 0052 bool barcodeRecognitionThread::isWebcamAvailable() 0053 { 0054 return m_barcode_v4l->isOpen(); 0055 } 0056 0057 QSize barcodeRecognitionThread::getPreviewSize() const 0058 { 0059 return QSize( 320,240 ); 0060 } 0061 0062 void barcodeRecognitionThread::run() 0063 { 0064 bool stop; 0065 m_stop_mutex.lock(); 0066 stop = m_stop; 0067 m_stop_mutex.unlock(); 0068 0069 if (!isWebcamAvailable()) 0070 stop = true; 0071 0072 Barcode_EAN13 old; 0073 while (!stop) { 0074 QImage img; 0075 m_barcode_img_mutex.lock(); 0076 if (m_barcode_img.isNull()) 0077 img = m_barcode_v4l->grab_one2(); 0078 else { 0079 img = m_barcode_img; 0080 m_barcode_img = QImage(); 0081 } 0082 m_barcode_img_mutex.unlock(); 0083 0084 // //DEBUG 0085 // img.load( "/home/sebastian/black.png" ); 0086 // m_stop = true; 0087 // //DEBUG 0088 0089 if (!img.isNull()) { 0090 QImage preview = img.scaled( 320, 240, Qt::KeepAspectRatio ); 0091 emit gotImage( preview ); 0092 Barcode_EAN13 barcode = recognize( img ); 0093 if (barcode.isValid() && (old != barcode)) { 0094 emit recognized( barcode.toString() ); 0095 old = barcode; 0096 } 0097 } 0098 msleep( 10 ); // reduce load 0099 0100 m_stop_mutex.lock(); 0101 stop = m_stop; 0102 m_stop_mutex.unlock(); 0103 } 0104 } 0105 0106 void barcodeRecognitionThread::stop() 0107 { 0108 // attention! This function is called from GUI context 0109 m_stop_mutex.lock(); 0110 m_stop = true; 0111 m_stop_mutex.unlock(); 0112 } 0113 0114 void barcodeRecognitionThread::recognizeBarcode( QImage img ) 0115 { 0116 // attention! This function is called from GUI context 0117 m_barcode_img_mutex.lock(); 0118 m_barcode_img = img; 0119 m_barcode_img_mutex.unlock(); 0120 } 0121 0122 Barcode_EAN13 barcodeRecognitionThread::recognize( QImage img ) 0123 { 0124 // PARAMETERS: 0125 int amount_scanlines = 30; 0126 int w = img.width(); 0127 int h = img.height(); 0128 0129 // the array which will contain the result: 0130 QVector< QVector<int> > numbers( amount_scanlines, QVector<int>(13,-1) ); // no init in java source!!!!!!!!! 0131 0132 // generate and initialize the array that will contain all detected 0133 // digits at a specific code position: 0134 int possible_numbers[10][13][2]; 0135 for (int i = 0; i < 10; i++) { 0136 for (int j = 0; j < 13; j++) { 0137 possible_numbers[i][j][0] = -1; 0138 possible_numbers[i][j][1] = 0; 0139 } 0140 } 0141 0142 // try to detect the barcode along scanlines: 0143 for (int i = 0; i < amount_scanlines; i++) { 0144 int x1 = 0; 0145 int y = (h / amount_scanlines) * i; 0146 int x2 = w - 1; 0147 0148 // try to recognize a barcode along that path: 0149 Barcode_EAN13 ean13_code = recognizeCode( img, x1, x2, y ); 0150 numbers[i] = ean13_code.getNumbers(); 0151 0152 if (ean13_code.isValid()) { 0153 // add the recognized digits to the array of possible numbers: 0154 addNumberToPossibleNumbers( numbers[i], possible_numbers, true ); 0155 } else { 0156 numbers[i] = ean13_code.getNumbers(); 0157 // add the recognized digits to the array of possible numbers: 0158 addNumberToPossibleNumbers(numbers[i], possible_numbers, false); 0159 } 0160 0161 #ifdef BarcodeDecoder_DEBUG 0162 // show the information that has been recognized along the scanline: 0163 qDebug( "Scanline %i result: %s\n", i, ean13_code.toString().latin1() ); 0164 #endif 0165 } 0166 0167 // sort the detected digits at each code position, in accordance to the 0168 // amount of their detection: 0169 sortDigits(possible_numbers); 0170 0171 #ifdef BarcodeDecoder_DEBUG 0172 fprintf( stderr, "detected digits:\n" ); 0173 printArray( possible_numbers, 0 ); 0174 fprintf( stderr, "# of their occurrence:\n" ); 0175 printArray( possible_numbers, 1 ); 0176 #endif 0177 0178 // get the most likely barcode: 0179 Barcode_EAN13 code = extractBarcode(possible_numbers); 0180 0181 return code; 0182 } 0183 0184 void barcodeRecognitionThread::printArray( int array[10][13][2], int level ) 0185 { 0186 for (int i = 0; i < 10; i++) { 0187 QString temp; 0188 temp = QString::number( i ) + QLatin1String(" : "); 0189 for (int j = 0; j < 13; j++) { 0190 if (array[i][j][level] == -1) 0191 temp += QLatin1String("x "); 0192 else 0193 temp += QString::number( array[i][j][level] ) + QLatin1String(" "); 0194 } 0195 qDebug() << temp; 0196 } 0197 } 0198 0199 barcodeRecognition::Barcode_EAN13 barcodeRecognitionThread::recognizeCode( QImage img, int x1, int x2, int y ) 0200 { 0201 QVector<QRgb> raw_path(x2-x1+1); 0202 for (int x=x1; x<=x2; x++) 0203 raw_path[x-x1] = img.pixel(x,y); 0204 // convert the given path into a string of black and white pixels: 0205 QVector<int> string = transformPathToBW( raw_path ); 0206 0207 // convert the string of black&white pixels into a list, containing 0208 // information about the black and white fields 0209 // first indes = field nr. 0210 // second index: 0 = color of the field 0211 // 1 = field length 0212 QVector< QVector<int> > fields = extractFieldInformation( string ); 0213 0214 // try to recognize a EAN13 code: 0215 Barcode_EAN13 barcode = Decoder_EAN13::recognize( fields ); 0216 0217 return barcode; 0218 } 0219 0220 void barcodeRecognitionThread::addNumberToPossibleNumbers( QVector<int> number, int possible_numbers[10][13][2], bool correct_code ) 0221 { 0222 int i; 0223 bool digit_contained; 0224 for (int j = 0; j < 13; j++) { 0225 if (number[j] >= 0) { 0226 i = 0; 0227 digit_contained = false; 0228 while ((i < 10) && (possible_numbers[i][j][0] >= 0)) { 0229 if (possible_numbers[i][j][0] == number[j]) { 0230 digit_contained = true; 0231 if (correct_code) 0232 possible_numbers[i][j][1] = possible_numbers[i][j][1] + 100; 0233 else 0234 possible_numbers[i][j][1]++; 0235 break; 0236 } 0237 i++; 0238 } 0239 if ((i < 10) && (!digit_contained)) { 0240 // add new digit: 0241 possible_numbers[i][j][0] = number[j]; 0242 if (correct_code) 0243 possible_numbers[i][j][1] = possible_numbers[i][j][1] + 100; 0244 else 0245 possible_numbers[i][j][1]++; 0246 } 0247 } 0248 } 0249 } 0250 0251 void barcodeRecognitionThread::sortDigits( int possible_numbers[10][13][2] ) 0252 { 0253 int i; 0254 int temp_value; 0255 int temp_occurrence; 0256 bool changes; 0257 0258 for (int j = 0; j < 13; j++) { 0259 i = 1; 0260 changes = false; 0261 while (true) { 0262 if ((possible_numbers[i - 1][j][0] >= 0) && (possible_numbers[i][j][0] >= 0)) { 0263 if (possible_numbers[i - 1][j][1] < possible_numbers[i][j][1]) { 0264 temp_value = possible_numbers[i - 1][j][0]; 0265 temp_occurrence = possible_numbers[i - 1][j][1]; 0266 possible_numbers[i - 1][j][0] = possible_numbers[i][j][0]; 0267 possible_numbers[i - 1][j][1] = possible_numbers[i][j][1]; 0268 possible_numbers[i][j][0] = temp_value; 0269 possible_numbers[i][j][1] = temp_occurrence; 0270 0271 changes = true; 0272 } 0273 } 0274 0275 if ((i >= 9) || (possible_numbers[i][j][0] < 0)) { 0276 if (!changes) 0277 break; 0278 else { 0279 i = 1; 0280 changes = false; 0281 } 0282 } else 0283 i++; 0284 } 0285 } 0286 } 0287 0288 Barcode_EAN13 barcodeRecognitionThread::extractBarcode( int possible_numbers[10][13][2] ) 0289 { 0290 // create and initialize the temporary variables: 0291 QVector<int> temp_code(13); 0292 for (int i = 0; i < 13; i++) 0293 temp_code[i] = possible_numbers[0][i][0]; 0294 0295 #ifdef Barcode_DEBUG 0296 fprintf( stderr, "barcodeRecognitionThread::extractBarcode(): " ); 0297 for (int i=0; i<13; i++) 0298 fprintf( stderr, "%i", temp_code[i] ); 0299 fprintf( stderr, "\n" ); 0300 #endif 0301 0302 return Barcode_EAN13(temp_code); 0303 } 0304 0305 Barcode_EAN13 barcodeRecognitionThread::detectValidBarcode ( int possible_numbers[10][13][2], int max_amount_of_considered_codes ) 0306 { 0307 // create and initialize the temporary variables: 0308 QVector<int> temp_code(13); 0309 for ( int i = 0; i < 13; i++ ) 0310 temp_code[i] = possible_numbers[0][i][0]; 0311 0312 int alternative_amount = 0; 0313 0314 QVector<int> counter( 13 ); // no init in java source!!! 0315 int counter_nr = 11; 0316 0317 // check if there is at least one complete code present: 0318 for ( int i = 0; i < 13; i++ ) { 0319 // exit and return the "most likely" code parts: 0320 if ( temp_code[i] < 0 ) 0321 return Barcode_EAN13( temp_code ); 0322 } 0323 0324 // if there is at least one complete node, try to detect a valid barcode: 0325 while ( alternative_amount < max_amount_of_considered_codes ) { 0326 // fill the temporary code array with one possible version: 0327 for ( int i = 0; i < 13; i++ ) 0328 temp_code[i] = possible_numbers[counter[i]][i][0]; 0329 0330 alternative_amount++; 0331 0332 // check if this version represents a valid code: 0333 if (isValid( temp_code )) 0334 return Barcode_EAN13( temp_code ); 0335 0336 // increment the counters: 0337 if ( ( counter[counter_nr] < 9 ) && ( possible_numbers[counter[counter_nr] + 1][counter_nr][0] >= 0 ) ) { 0338 // increment the actual counter. 0339 counter[counter_nr]++; 0340 } else { 0341 // check if we have reached the end and no valid barcode has been found: 0342 if ( counter_nr == 1 ) { 0343 // exit and return the "most likely" code parts: 0344 for ( int i = 0; i < 13; i++ ) 0345 temp_code[i] = possible_numbers[0][i][0]; 0346 return Barcode_EAN13( temp_code ); 0347 } else { 0348 // reset the actual counter and increment the next one(s): 0349 counter[counter_nr] = 0; 0350 0351 while ( true ) { 0352 if ( counter_nr > 2 ) 0353 counter_nr--; 0354 else { 0355 for ( int i = 0; i < 13; i++ ) 0356 temp_code[i] = possible_numbers[0][i][0]; 0357 return Barcode_EAN13( temp_code ); 0358 } 0359 if ( counter[counter_nr] < 9 ) { 0360 counter[counter_nr]++; 0361 if ( possible_numbers[counter[counter_nr]][counter_nr][0] < 0 ) 0362 counter[counter_nr] = 0; 0363 else 0364 break; 0365 } else 0366 counter[counter_nr] = 0; 0367 } 0368 counter_nr = 12; 0369 } 0370 } 0371 } 0372 0373 for ( int i = 0; i < 13; i++ ) 0374 temp_code[i] = possible_numbers[0][i][0]; 0375 return Barcode_EAN13( temp_code ); 0376 } 0377 0378 bool barcodeRecognitionThread::isValid( int numbers[13] ) 0379 { 0380 QVector<int> temp(13); 0381 for (int i=0; i<13; i++) 0382 temp[i] = numbers[i]; 0383 return isValid( temp ); 0384 } 0385 bool barcodeRecognitionThread::isValid( QVector<int> numbers ) 0386 { 0387 Q_ASSERT( numbers.count() == 13 ); 0388 // calculate the checksum of the barcode: 0389 int sum1 = numbers[0] + numbers[2] + numbers[4] + numbers[6] + numbers[8] + numbers[10]; 0390 int sum2 = 3 * (numbers[1] + numbers[3] + numbers[5] + numbers[7] + numbers[9] + numbers[11]); 0391 int checksum_value = sum1 + sum2; 0392 int checksum_digit = 10 - (checksum_value % 10); 0393 if (checksum_digit == 10) 0394 checksum_digit = 0; 0395 0396 #ifdef Barcode_DEBUG 0397 fprintf( stderr, "barcodeRecognitionThread::isValid(): " ); 0398 for (int i=0; i<13; i++) 0399 fprintf( stderr, "%i", numbers[i] ); 0400 fprintf( stderr, "\n" ); 0401 #endif 0402 0403 return (numbers[12] == checksum_digit); 0404 } 0405 0406 QVector<int> barcodeRecognitionThread::transformPathToBW( QVector<QRgb> line ) 0407 { 0408 int w = line.count(); 0409 QVector<int> bw_line(w,0); 0410 bw_line[0] = 255; 0411 0412 // create greyscale values: 0413 QVector<int> grey_line(w,0); 0414 int average_illumination = 0; 0415 for (int x = 0; x < w; x++) { 0416 grey_line[x] = (qRed(line.at(x)) + qGreen(line.at(x)) + qBlue(line.at(x))) / 3; 0417 average_illumination = average_illumination + grey_line[x]; 0418 } 0419 average_illumination = average_illumination / w; 0420 0421 // perform the binarization: 0422 int range = w / 20; 0423 0424 // temp values: 0425 int moving_sum; 0426 int moving_average; 0427 int v1_index = -range + 1; 0428 int v2_index = range; 0429 int v1 = grey_line[0]; 0430 int v2 = grey_line[range]; 0431 int current_value; 0432 int comparison_value; 0433 0434 // initialize the moving sum: 0435 moving_sum = grey_line[0] * range; 0436 for (int i = 0; i < range; i++) 0437 moving_sum = moving_sum + grey_line[i]; 0438 0439 // apply the adaptive thresholding algorithm: 0440 for (int i = 1; i < w - 1; i++) { 0441 if (v1_index > 0) v1 = grey_line[v1_index]; 0442 if (v2_index < w) v2 = grey_line[v2_index]; 0443 else v2 = grey_line[w - 1]; 0444 moving_sum = moving_sum - v1 + v2; 0445 moving_average = moving_sum / (range << 1); 0446 v1_index++; 0447 v2_index++; 0448 0449 current_value = (grey_line[i - 1] + grey_line[i]) >> 1; 0450 0451 // decide if the current pixel should be black or white: 0452 comparison_value = (3 * moving_average + average_illumination) >> 2; 0453 if ((current_value < comparison_value - 3)) bw_line[i] = 0; 0454 else bw_line[i] = 255; 0455 } 0456 0457 // filter the values: (remove too small fields) 0458 0459 if (w >= 640) { 0460 for (int x = 1; x < w - 1; x++) { 0461 if ((bw_line[x] != bw_line[x - 1]) && (bw_line[x] != bw_line[x + 1])) bw_line[x] = bw_line[x - 1]; 0462 } 0463 } 0464 0465 QVector<int> ret(w,0); 0466 for (int i=0; i<w; i++) 0467 ret[i] = bw_line[i]; 0468 0469 #ifdef Barcode_DEBUG 0470 fprintf( stderr, "barcodeRecognitionThread::transformPathToBW(): " ); 0471 for (int i=0; i<ret.count(); i++) 0472 if (bw_line[i] == 0) 0473 fprintf( stderr, "0" ); 0474 else 0475 fprintf( stderr, "#" ); 0476 fprintf( stderr, "\n" ); 0477 #endif 0478 0479 return ret; 0480 } 0481 0482 QVector< QVector<int> > barcodeRecognitionThread::extractFieldInformation( QVector<int> string ) 0483 { 0484 QVector< QVector<int> > temp_fields( string.count(), QVector<int>(2,0) ); 0485 0486 if (string.count() == 0) 0487 return QVector< QVector<int> >(); 0488 0489 int field_counter = 0; 0490 int last_value = string.at(0); 0491 int last_fields = 1; 0492 for (int i = 1; i < string.size(); i++) { 0493 if ((string.at(i) == last_value) && (i < string.size() - 1)) { 0494 last_fields++; 0495 } else { 0496 // create new field entry: 0497 temp_fields[field_counter][0] = last_value; 0498 temp_fields[field_counter][1] = last_fields; 0499 0500 last_value = string.at(i); 0501 last_fields = 0; 0502 field_counter++; 0503 } 0504 } 0505 0506 temp_fields.resize( field_counter ); 0507 0508 #ifdef Barcode_DEBUG 0509 fprintf( stderr, "barcodeRecognitionThread::extractFieldInformation(): " ); 0510 for (int i=0; i<temp_fields.count(); i++) 0511 fprintf( stderr, "%i,%i ", temp_fields.at(i).at(0), temp_fields.at(i).at(1) ); 0512 fprintf( stderr, "\n" ); 0513 #endif 0514 0515 return temp_fields; 0516 } 0517 0518 //ok 0519 Barcode_EAN13::Barcode_EAN13() : m_numbers(13,-1) 0520 { 0521 m_null = true; 0522 } 0523 0524 //ok 0525 Barcode_EAN13::Barcode_EAN13( QVector<int> code ) 0526 { 0527 setCode( code ); 0528 } 0529 0530 //ok 0531 void Barcode_EAN13::setCode( QVector<int> code ) 0532 { 0533 if (code.count() != 13) { 0534 m_numbers.clear(); 0535 m_numbers.insert(0,13,-1); 0536 m_null = true; 0537 return; 0538 } 0539 m_numbers = code; 0540 m_null = false; 0541 } 0542 0543 //ok 0544 bool Barcode_EAN13::isValid() const 0545 { 0546 if (m_null) 0547 return false; 0548 0549 for (int i = 0; i < 13; i++) 0550 if ((m_numbers[i] < 0) || (m_numbers[i] > 9)) 0551 return false; 0552 0553 // calculate the checksum of the barcode: 0554 int sum1 = m_numbers[0] + m_numbers[2] + m_numbers[4] + m_numbers[6] + m_numbers[8] + m_numbers[10]; 0555 int sum2 = 3 * (m_numbers[1] + m_numbers[3] + m_numbers[5] + m_numbers[7] + m_numbers[9] + m_numbers[11]); 0556 int checksum_value = sum1 + sum2; 0557 int checksum_digit = 10 - (checksum_value % 10); 0558 if (checksum_digit == 10) 0559 checksum_digit = 0; 0560 0561 return (m_numbers[12] == checksum_digit); 0562 } 0563 0564 //ok 0565 QVector<int> Barcode_EAN13::getNumbers() const 0566 { 0567 return m_numbers; 0568 } 0569 0570 //ok 0571 QString Barcode_EAN13::toString() const 0572 { 0573 QString s; 0574 for (int i = 0; i < 13; i++) 0575 if ((m_numbers[i] >= 0) && (m_numbers[i] <= 9)) 0576 s += QString::number(m_numbers[i]); 0577 else 0578 s += QChar::fromLatin1('?'); 0579 return s; 0580 } 0581 0582 //ok 0583 bool Barcode_EAN13::operator!= ( const Barcode_EAN13 &code ) 0584 { 0585 if (m_null != code.m_null) 0586 return true; 0587 if (!m_null) 0588 for (int i=0; i<13; i++) 0589 if (m_numbers[i] != code.m_numbers[i]) 0590 return true; 0591 return false; 0592 } 0593 0594 //ok 0595 Barcode_EAN13 Decoder_EAN13::recognize( QVector< QVector<int> > fields ) 0596 { 0597 // try to extract the encoded information from the field series: 0598 QVector<int> numbers = decode( fields, 0, fields.count() ); 0599 Barcode_EAN13 barcode( numbers ); 0600 0601 // return the results: 0602 return barcode; 0603 } 0604 0605 QVector<int> Decoder_EAN13::decode( QVector< QVector<int> > fields, int start_i, int end_i ) 0606 { 0607 // determine the length of the path in pixels 0608 int length = 0; 0609 for (int i = 0; i < fields.size(); i++) 0610 length += fields.at(i).at(1); 0611 0612 // set the parameters accordingly: 0613 int max_start_sentry_bar_differences; 0614 int max_unit_length; 0615 int min_unit_length; 0616 0617 if (length <= 800) { 0618 max_start_sentry_bar_differences = 6; 0619 max_unit_length = 10; 0620 min_unit_length = 1; 0621 } else { 0622 max_start_sentry_bar_differences = 30; 0623 max_unit_length = 50; 0624 min_unit_length = 1; 0625 } 0626 0627 // consistency checks: 0628 if (fields.count() <= 0) 0629 return QVector<int>(); 0630 if (start_i > end_i - 3) 0631 return QVector<int>(); 0632 if (end_i - start_i < 30) 0633 return QVector<int>(); // (just a rough value) 0634 0635 // relevant indexes: 0636 int start_sentinel_i; 0637 int end_sentinel_i; 0638 int left_numbers_i; 0639 int middle_guard_i; 0640 int right_numbers_i; 0641 0642 // results: 0643 QVector<int> numbers( 13, -1 ); // the java source does no initialization 0644 0645 // determine the relevant positions: 0646 0647 // Try to detect the start sentinel (a small black-white-black serie): 0648 start_sentinel_i = -1; 0649 for (int i = start_i; i < end_i - 56; i++) { 0650 if (fields[i][0] == 0) { 0651 if ((fields[i][1] >= min_unit_length) && (fields[i][1] <= max_unit_length)) { 0652 if ((qAbs(fields[i][1] - fields[i + 1][1]) <= max_start_sentry_bar_differences) 0653 && (qAbs(fields[i][1] - fields[i + 2][1]) <= max_start_sentry_bar_differences) && (fields[i + 3][1] < fields[i][1] << 3)) { 0654 start_sentinel_i = i; 0655 break; 0656 } 0657 } 0658 } 0659 } 0660 0661 #ifdef Decoder_EAN13_DEBUG 0662 fprintf( stderr, "start_sentinal_index: %i\n", start_sentinel_i ); 0663 #endif 0664 0665 if (start_sentinel_i < 0) 0666 return QVector<int>(); 0667 0668 // calculate the other positions: 0669 left_numbers_i = start_sentinel_i + 3; 0670 middle_guard_i = left_numbers_i + 6 * 4; 0671 right_numbers_i = middle_guard_i + 5; 0672 end_sentinel_i = right_numbers_i + 6 * 4; 0673 0674 if (end_sentinel_i + 3 > end_i) 0675 return QVector<int>(); 0676 0677 QVector< QVector<int> > current_number_field( 4, QVector<int>(2,0) ); 0678 0679 if (left_numbers_i + 1 > end_i) 0680 return QVector<int>(); 0681 0682 // test the side from which we are reading the barcode: 0683 for (int j = 0; j < 4; j++) { 0684 current_number_field[j][0] = fields[left_numbers_i + j][0]; 0685 current_number_field[j][1] = fields[left_numbers_i + j][1]; 0686 } 0687 MatchMakerResult matchMakerResult = recognizeNumber( current_number_field, BOTH_TABLES ); 0688 0689 if (matchMakerResult.isEven()) { 0690 // we are reading the barcode from the back side: 0691 0692 // use the already obtained information: 0693 numbers[12] = matchMakerResult.getDigit(); 0694 0695 // try to recognize the "right" numbers: 0696 int counter = 11; 0697 for (int i = left_numbers_i + 4; i < left_numbers_i + 24; i = i + 4) { 0698 for (int j = 0; j < 4; j++) { 0699 current_number_field[j][0] = fields[i + j][0]; 0700 current_number_field[j][1] = fields[i + j][1]; 0701 } 0702 matchMakerResult = recognizeNumber(current_number_field, EVEN_TABLE); 0703 numbers[counter] = matchMakerResult.getDigit(); 0704 counter--; 0705 } 0706 0707 bool parity_pattern[6]; // true = even, false = odd 0708 0709 //(counter has now the value 6) 0710 0711 // try to recognize the "left" numbers: 0712 for (int i = right_numbers_i; i < right_numbers_i + 24; i = i + 4) { 0713 for (int j = 0; j < 4; j++) { 0714 current_number_field[j][0] = fields[i + j][0]; 0715 current_number_field[j][1] = fields[i + j][1]; 0716 } 0717 matchMakerResult = recognizeNumber(current_number_field, BOTH_TABLES); 0718 numbers[counter] = matchMakerResult.getDigit(); 0719 parity_pattern[counter-1] = !matchMakerResult.isEven(); 0720 counter--; 0721 } 0722 0723 // try to determine the system code: 0724 matchMakerResult = recognizeSystemCode(parity_pattern); 0725 numbers[0] = matchMakerResult.getDigit(); 0726 } else { 0727 // we are reading the barcode from the "correct" side: 0728 0729 bool parity_pattern[6]; // true = even, false = odd 0730 0731 // use the already obtained information: 0732 numbers[1] = matchMakerResult.getDigit(); 0733 parity_pattern[0] = matchMakerResult.isEven(); 0734 0735 // try to recognize the left numbers: 0736 int counter = 2; 0737 for (int i = left_numbers_i + 4; i < left_numbers_i + 24; i = i + 4) { 0738 for (int j = 0; j < 4; j++) { 0739 current_number_field[j][0] = fields[i + j][0]; 0740 current_number_field[j][1] = fields[i + j][1]; 0741 } 0742 matchMakerResult = recognizeNumber(current_number_field, BOTH_TABLES); 0743 numbers[counter] = matchMakerResult.getDigit(); 0744 parity_pattern[counter-1] = matchMakerResult.isEven(); 0745 counter++; 0746 } 0747 0748 // try to determine the system code: 0749 matchMakerResult = recognizeSystemCode(parity_pattern); 0750 numbers[0] = matchMakerResult.getDigit(); 0751 0752 // try to recognize the right numbers: 0753 counter = 0; 0754 for (int i = right_numbers_i; i < right_numbers_i + 24; i = i + 4) { 0755 for (int j = 0; j < 4; j++) { 0756 current_number_field[j][0] = fields[i + j][0]; 0757 current_number_field[j][1] = fields[i + j][1]; 0758 } 0759 matchMakerResult = recognizeNumber(current_number_field, ODD_TABLE); 0760 numbers[counter + 7] = matchMakerResult.getDigit(); 0761 counter++; 0762 } 0763 } 0764 0765 return numbers; 0766 } 0767 0768 MatchMakerResult Decoder_EAN13::recognizeNumber( QVector< QVector<int> > fields, int code_table_to_use) 0769 { 0770 // convert the pixel lengths of the four black&white fields into 0771 // normed values that have together a length of 70; 0772 int pixel_sum = fields[0][1] + fields[1][1] + fields[2][1] + fields[3][1]; 0773 int b[4]; 0774 for (int i = 0; i < 4; i++) { 0775 b[i] = ::round((((float) fields[i][1]) / ((float) pixel_sum)) * 70); 0776 } 0777 0778 #ifdef Decoder_EAN13_DEBUG 0779 fprintf( stderr, "Recognize Number (code table to use: %i):\n", code_table_to_use ); 0780 fprintf( stderr, "lengths: %i %i %i %i\n", fields[0][1], fields[1][1], fields[2][1], fields[3][1] ); 0781 fprintf( stderr, "normed lengths: %i %i %i %i\n", b[0], b[1], b[2], b[3] ); 0782 #endif 0783 0784 // try to detect the digit that is encoded by the set of four normed bar lengths: 0785 int max_difference_for_acceptance = 60; 0786 int temp; 0787 0788 int even_min_difference = 100000; 0789 int even_min_difference_index = 0; 0790 int odd_min_difference = 100000; 0791 int odd_min_difference_index = 0; 0792 0793 if ((code_table_to_use == BOTH_TABLES)||(code_table_to_use == EVEN_TABLE)) { 0794 QVector<int> even_differences(10,0); 0795 0796 for (int i = 0; i < 10; i++) { 0797 for (int j = 0; j < 4; j++) { 0798 // calculate the differences in the even group: 0799 temp = b[j] - code_even[i][j]; 0800 if (temp < 0) 0801 even_differences[i] = even_differences[i] + ((-temp) << 1); 0802 else 0803 even_differences[i] = even_differences[i] + (temp << 1); 0804 } 0805 if (even_differences[i] < even_min_difference) { 0806 even_min_difference = even_differences[i]; 0807 even_min_difference_index = i; 0808 } 0809 } 0810 } 0811 0812 if ((code_table_to_use == BOTH_TABLES) || (code_table_to_use == ODD_TABLE)) { 0813 QVector<int> odd_differences(10,0); 0814 0815 for (int i = 0; i < 10; i++) { 0816 for (int j = 0; j < 4; j++) { 0817 // calculate the differences in the odd group: 0818 temp = b[j] - code_odd[i][j]; 0819 if (temp < 0) 0820 odd_differences[i] = odd_differences[i] + ((-temp) << 1); 0821 else 0822 odd_differences[i] = odd_differences[i] + (temp << 1); 0823 } 0824 if (odd_differences[i] < odd_min_difference) { 0825 odd_min_difference = odd_differences[i]; 0826 odd_min_difference_index = i; 0827 } 0828 } 0829 } 0830 0831 // select the digit and parity with the lowest difference to the found pattern: 0832 if (even_min_difference <= odd_min_difference) { 0833 if (even_min_difference < max_difference_for_acceptance) 0834 return MatchMakerResult( true, even_min_difference_index ); 0835 } else { 0836 if (odd_min_difference < max_difference_for_acceptance) 0837 return MatchMakerResult( false, odd_min_difference_index ); 0838 } 0839 0840 return MatchMakerResult( false, -1 ); 0841 } 0842 0843 MatchMakerResult Decoder_EAN13::recognizeSystemCode( bool parity_pattern[6] ) 0844 { 0845 // search for a fitting parity pattern: 0846 bool fits = false; 0847 for (int i = 0; i < 10; i++) { 0848 fits = true; 0849 for (int j = 0; j < 6; j++) { 0850 if (parity_pattern_list[i][j] != parity_pattern[j]) { 0851 fits = false; 0852 break; 0853 } 0854 } 0855 if (fits) 0856 return MatchMakerResult( false, i ); 0857 } 0858 0859 return MatchMakerResult( false, -1 ); 0860 } 0861 0862 //ok 0863 MatchMakerResult::MatchMakerResult( bool even, int digit ) 0864 { 0865 m_even = even; 0866 m_digit = digit; 0867 }