qrcode.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/env python
  2. '''
  3. This program detects the QR-codes using OpenCV Library.
  4. Usage:
  5. qrcode.py
  6. '''
  7. # Python 2/3 compatibility
  8. from __future__ import print_function
  9. import numpy as np
  10. import cv2 as cv
  11. import argparse
  12. import sys
  13. PY3 = sys.version_info[0] == 3
  14. if PY3:
  15. xrange = range
  16. class QrSample:
  17. def __init__(self, args):
  18. self.fname = ''
  19. self.fext = ''
  20. self.fsaveid = 0
  21. self.input = args.input
  22. self.detect = args.detect
  23. self.out = args.out
  24. self.multi = args.multi
  25. self.saveDetections = args.save_detections
  26. self.saveAll = args.save_all
  27. def getQRModeString(self):
  28. msg1 = "multi " if self.multi else ""
  29. msg2 = "detector" if self.detect else "decoder"
  30. msg = "QR {:s}{:s}".format(msg1, msg2)
  31. return msg
  32. def drawFPS(self, result, fps):
  33. message = '{:.2f} FPS({:s})'.format(fps, self.getQRModeString())
  34. cv.putText(result, message, (20, 20), 1,
  35. cv.FONT_HERSHEY_DUPLEX, (0, 0, 255))
  36. def drawQRCodeContours(self, image, cnt):
  37. if cnt.size != 0:
  38. rows, cols, _ = image.shape
  39. show_radius = 2.813 * ((rows / cols) if rows > cols else (cols / rows))
  40. contour_radius = show_radius * 0.4
  41. cv.drawContours(image, [cnt], 0, (0, 255, 0), int(round(contour_radius)))
  42. tpl = cnt.reshape((-1, 2))
  43. for x in tuple(tpl.tolist()):
  44. color = (255, 0, 0)
  45. cv.circle(image, tuple(x), int(round(contour_radius)), color, -1)
  46. def drawQRCodeResults(self, result, points, decode_info, fps):
  47. n = len(points)
  48. if isinstance(decode_info, str):
  49. decode_info = [decode_info]
  50. if n > 0:
  51. for i in range(n):
  52. cnt = np.array(points[i]).reshape((-1, 1, 2)).astype(np.int32)
  53. self.drawQRCodeContours(result, cnt)
  54. msg = 'QR[{:d}]@{} : '.format(i, *(cnt.reshape(1, -1).tolist()))
  55. print(msg, end="")
  56. if len(decode_info) > i:
  57. if decode_info[i]:
  58. print("'", decode_info[i], "'")
  59. else:
  60. print("Can't decode QR code")
  61. else:
  62. print("Decode information is not available (disabled)")
  63. else:
  64. print("QRCode not detected!")
  65. self.drawFPS(result, fps)
  66. def runQR(self, qrCode, inputimg):
  67. if not self.multi:
  68. if not self.detect:
  69. decode_info, points, _ = qrCode.detectAndDecode(inputimg)
  70. dec_info = decode_info
  71. else:
  72. _, points = qrCode.detect(inputimg)
  73. dec_info = []
  74. else:
  75. if not self.detect:
  76. _, decode_info, points, _ = qrCode.detectAndDecodeMulti(
  77. inputimg)
  78. dec_info = decode_info
  79. else:
  80. _, points = qrCode.detectMulti(inputimg)
  81. dec_info = []
  82. if points is None:
  83. points = []
  84. return points, dec_info
  85. def DetectQRFrmImage(self, inputfile):
  86. inputimg = cv.imread(inputfile, cv.IMREAD_COLOR)
  87. if inputimg is None:
  88. print('ERROR: Can not read image: {}'.format(inputfile))
  89. return
  90. print('Run {:s} on image [{:d}x{:d}]'.format(
  91. self.getQRModeString(), inputimg.shape[1], inputimg.shape[0]))
  92. qrCode = cv.QRCodeDetector()
  93. count = 10
  94. timer = cv.TickMeter()
  95. for _ in range(count):
  96. timer.start()
  97. points, decode_info = self.runQR(qrCode, inputimg)
  98. timer.stop()
  99. fps = count / timer.getTimeSec()
  100. print('FPS: {}'.format(fps))
  101. result = inputimg
  102. self.drawQRCodeResults(result, points, decode_info, fps)
  103. cv.imshow("QR", result)
  104. cv.waitKey(1)
  105. if self.out != '':
  106. outfile = self.fname + self.fext
  107. print("Saving Result: {}".format(outfile))
  108. cv.imwrite(outfile, result)
  109. print("Press any key to exit ...")
  110. cv.waitKey(0)
  111. print("Exit")
  112. def processQRCodeDetection(self, qrcode, frame):
  113. if len(frame.shape) == 2:
  114. result = cv.cvtColor(frame, cv.COLOR_GRAY2BGR)
  115. else:
  116. result = frame
  117. print('Run {:s} on video frame [{:d}x{:d}]'.format(
  118. self.getQRModeString(), frame.shape[1], frame.shape[0]))
  119. timer = cv.TickMeter()
  120. timer.start()
  121. points, decode_info = self.runQR(qrcode, frame)
  122. timer.stop()
  123. fps = 1 / timer.getTimeSec()
  124. self.drawQRCodeResults(result, points, decode_info, fps)
  125. return fps, result, points
  126. def DetectQRFrmCamera(self):
  127. cap = cv.VideoCapture(0)
  128. if not cap.isOpened():
  129. print("Cannot open the camera")
  130. return
  131. print("Press 'm' to switch between detectAndDecode and detectAndDecodeMulti")
  132. print("Press 'd' to switch between decoder and detector")
  133. print("Press ' ' (space) to save result into images")
  134. print("Press 'ESC' to exit")
  135. qrcode = cv.QRCodeDetector()
  136. while True:
  137. ret, frame = cap.read()
  138. if not ret:
  139. print("End of video stream")
  140. break
  141. forcesave = self.saveAll
  142. result = frame
  143. try:
  144. fps, result, corners = self.processQRCodeDetection(qrcode, frame)
  145. print('FPS: {:.2f}'.format(fps))
  146. forcesave |= self.saveDetections and (len(corners) != 0)
  147. except cv.error as e:
  148. print("Error exception: ", e)
  149. forcesave = True
  150. cv.imshow("QR code", result)
  151. code = cv.waitKey(1)
  152. if code < 0 and (not forcesave):
  153. continue
  154. if code == ord(' ') or forcesave:
  155. fsuffix = '-{:05d}'.format(self.fsaveid)
  156. self.fsaveid += 1
  157. fname_in = self.fname + fsuffix + "_input.png"
  158. print("Saving QR code detection result: '{}' ...".format(fname_in))
  159. cv.imwrite(fname_in, frame)
  160. print("Saved")
  161. if code == ord('m'):
  162. self.multi = not self.multi
  163. msg = 'Switching QR code mode ==> {:s}'.format(
  164. "detectAndDecodeMulti" if self.multi else "detectAndDecode")
  165. print(msg)
  166. if code == ord('d'):
  167. self.detect = not self.detect
  168. msg = 'Switching QR code mode ==> {:s}'.format(
  169. "detect" if self.detect else "decode")
  170. print(msg)
  171. if code == 27:
  172. print("'ESC' is pressed. Exiting...")
  173. break
  174. print("Exit.")
  175. def main():
  176. parser = argparse.ArgumentParser(
  177. description='This program detects the QR-codes input images using OpenCV Library.')
  178. parser.add_argument(
  179. '-i',
  180. '--input',
  181. help="input image path (for example, 'opencv_extra/testdata/cv/qrcode/multiple/*_qrcodes.png)",
  182. default="",
  183. metavar="")
  184. parser.add_argument(
  185. '-d',
  186. '--detect',
  187. help="detect QR code only (skip decoding) (default: False)",
  188. action='store_true')
  189. parser.add_argument(
  190. '-m',
  191. '--multi',
  192. help="enable multiple qr-codes detection",
  193. action='store_true')
  194. parser.add_argument(
  195. '-o',
  196. '--out',
  197. help="path to result file (default: qr_code.png)",
  198. default="qr_code.png",
  199. metavar="")
  200. parser.add_argument(
  201. '--save_detections',
  202. help="save all QR detections (video mode only)",
  203. action='store_true')
  204. parser.add_argument(
  205. '--save_all',
  206. help="save all processed frames (video mode only)",
  207. action='store_true')
  208. args = parser.parse_args()
  209. qrinst = QrSample(args)
  210. if args.out != '':
  211. index = args.out.rfind('.')
  212. if index != -1:
  213. qrinst.fname = args.out[:index]
  214. qrinst.fext = args.out[index:]
  215. else:
  216. qrinst.fname = args.out
  217. qrinst.fext = ".png"
  218. if args.input != '':
  219. qrinst.DetectQRFrmImage(args.input)
  220. else:
  221. qrinst.DetectQRFrmCamera()
  222. if __name__ == '__main__':
  223. print(__doc__)
  224. main()
  225. cv.destroyAllWindows()