pogucam 0.1.12__py3-none-any.whl → 0.1.14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -83,6 +83,17 @@ import math
83
83
 
84
84
  from astropy import wcs
85
85
 
86
+ #------------------------------------ subscibe
87
+ import struct
88
+ import paho.mqtt.client as mqtt
89
+ import numpy as np
90
+ import datetime as dt
91
+ import cv2
92
+ import threading
93
+
94
+
95
+
96
+
86
97
  istrip = 0
87
98
  UPDATE_INTERVAL = 1
88
99
  #FITS_CUBE_N = 400
@@ -157,7 +168,10 @@ def is_int(n):
157
168
 
158
169
  def guess_url( inp ):
159
170
  """
160
- interpret url like http or /dev/
171
+ interpret url: http: or /dev/
172
+ - low integer== dev
173
+ - int 80+ is local port; http+ is clear;
174
+ - :1883/topic/var or :1883
161
175
  """
162
176
  final = inp
163
177
  ip = ""
@@ -166,7 +180,29 @@ def guess_url( inp ):
166
180
  if inp is None:
167
181
  print("X... no url")
168
182
  return None
169
- if type(inp) is int:
183
+ if inp[0] == ":":
184
+ port = "".join(inp[1:])
185
+ path = port.split("/")[1:]
186
+ path = "/".join(path)
187
+ port = port.split("/")[0]
188
+ print("D... port is evidently given in ", inp[1:], "; port:", port, "path:" , path)
189
+ if not is_int(port):
190
+ print("X... port not integer")
191
+ return None
192
+ port = int(port)
193
+ if port == 1883:
194
+ final = f"mqtt://127.0.0.1/{path}"
195
+ print("i... local mqtt ... ", final)
196
+ return final
197
+ else:
198
+ final = f"http://127.0.0.1:{port}/{path}"
199
+ print("i... local http ... ", final)
200
+ return final
201
+ #return inp
202
+ if inp.find("/dev/video") == 0:
203
+ print("D... no discussion, videodev:", inp)
204
+ return inp
205
+ if type(inp) is int:# dev # or port #
170
206
  if int(inp) < 80:
171
207
  print("D... maybe video device")
172
208
  videostr = f"/dev/video{inp}"
@@ -183,65 +219,96 @@ def guess_url( inp ):
183
219
  return final
184
220
  print("X... IDK:")
185
221
  return None
186
-
222
+ # clearly mqtt
223
+ if (inp.find("mqtt://") == 0):
224
+ print("i... clearly mqtt:", inp)
225
+ return final
226
+ # clearly http
187
227
  if (inp.find("http://") == 0) or (inp.find("https://") == 0):
188
228
  if (inp.find(":") > 0):
189
229
  return final
190
230
  else:
191
231
  print("X... a problem, no port demanded")
192
232
  return None
233
+ # something strange, less than any IP ... IDK
193
234
  elif len(inp) < 7:
194
- print("X... TOO short ip (can be 0 for viceo0):", inp)
235
+ print("X... /ShoudntBeHere/ TOO short ip (can be 0 for video0):", inp)
195
236
  if is_int(inp):
196
- print("i... but is is one number, possibly port number", inp)
197
- if int(inp) > 79 and int(inp) < 64000:
198
- print("i... I put 127.0.0.1 address ")
237
+ print("i... /ShoudntBeHere/ but this is one number, possibly port number", inp)
238
+ if int(inp) > 79 and int(inp) < 64000 and int(inp) != 1883:
239
+ print("i... /ShoudntBeHere/I put 127.0.0.1 address ")
199
240
  final = f"http://127.0.0.1:{inp}/video"
200
241
  return final
242
+ elif int(inp) == 1883:
243
+ print("i... mqtt is evidently required. Topic (too short inp) is: ", path)
244
+ # if inp.find("/") > 0:
245
+ # port = inp.split("/")[]
246
+ # path = join("/").portplus.split("/")[1:]
247
+ if path == "":
248
+ print("i... topic will be by default image/raw8000")
249
+ path = "image/raw8000"
250
+ ip = "127.0.0.1"
251
+ final = f"mqtt://{ip}/{path}"
252
+ print(final)
253
+ return final
201
254
  elif is_int(inp):
202
- print("D... maybe video device")
255
+ print("D... /ShoudntBeHere/maybe video device")
203
256
  videostr = f"/dev/video{inp}"
204
257
  if os.path.exists( videostr):
205
- print(f"i... {videostr} exists ")
258
+ print(f"i... /ShoudntBeHere/ {videostr} exists ")
206
259
  return videostr
207
260
  else:
208
- print(f"i... {videostr} DOES NOT exist !!!!! ")
261
+ print(f"i... /ShoudntBeHere/ {videostr} DOES NOT exist !!!!! ")
209
262
  return videostr
210
263
  else:
211
- print("X... BAD input", inp)
264
+ print("X... /ShoudntBeHere-maybe/ BAD input", inp)
265
+ return None
266
+ # address
212
267
  elif inp.find(".") < 0:
213
- print("X... no dots in address ", inp)
268
+ print("X... no dots in the address ", inp)
214
269
  return None
215
270
  elif len(inp.split(".")) < 3:
216
- print("X... not IP4 address ", inp)
271
+ print("X... too few dots, not IP4 address ", inp)
217
272
  return None
218
273
  # ----------------------------------------------
219
274
  digit = inp.split(".")
220
- if is_int( digit[0]) and is_int(digit[1]) and is_int(digit[2]):
275
+ if is_int( digit[0]) and is_int(digit[1]) and is_int(digit[2]): # 3 digits and d:port
221
276
  # DIGITS
222
277
  if is_int(digit[3]):
223
- print("X... a bit problem, no port demanded at 3rd digit", digit, " giving 8000")
278
+ print("i... a bit of problem, no port demanded at 3rd digit", digit, " giving 8000")
224
279
  ip = inp # back to 4 digits
225
280
  port = "8000"
226
281
  #return None
227
- elif digit[3].find(":") <= 0:
228
- print("X... a bit problem, no port demanded, giving 8000")
282
+ elif digit[3].find(":") <= 0: # if not a digit, maybe path??
283
+ print("X... /ShoudntBeHere-maybe/ a bit of problem, no port demanded, giving 8000")
229
284
  port = "8000"
230
285
  #return None
231
- else:# port ok
286
+ else:# port ok-extract
232
287
  ip = inp.split(":")[0]
233
288
  portplus = inp.split(":")[1]
289
+ # extract path
234
290
  if portplus.find("/") > 0:
235
291
  port = portplus.split("/")[0]
236
- path = join("/").portplus.split("/")[1:]
292
+ pathlist = portplus.split("/")[1:]
293
+ path = "/".join(pathlist)
237
294
  else:
238
295
  port = portplus
239
-
296
+ # ---
240
297
  if not is_int(port):
241
- print("X... port is not a number", port)
298
+ print("X... port is not a number:", port)
242
299
  return None
300
+ # port is OK now----------------------------
301
+ port = int(port)
302
+ if port == 1883:
303
+ print("i... mqtt is evidently required. Topic is: ", path)
304
+ if path == "":
305
+ print("i... topic will be by default image/raw8000")
306
+ path = "image/raw8000"
307
+ final = f"mqtt://{ip}:{port}/{path}"
308
+ print(final)
309
+ return final
243
310
  if path == "":
244
- print("X... a bit problem, no path. Giving /video")
311
+ print("i... a bit problem, no path obtained. Giving /video , but this should probably change in future")
245
312
  path = "video"
246
313
 
247
314
  final = f"http://{ip}:{port}/{path}"
@@ -379,32 +446,42 @@ class StreamWidget(QLabel):
379
446
  self.device = None
380
447
  self.url = None
381
448
  self.post_addr = None
382
- ######self.internet_not_device = None
383
-
449
+ self.internet_mqtt = False
450
+ self.mqtt_topic = "image/raw8000" # default topic
451
+ self.mqtt_subscribed = False
452
+ self.mqtt_client = None
453
+ self.mqtt_new_image = False # trafic light
454
+ # url is mqtt:// of http:// or /dev/
384
455
  if url is None :
385
456
  print("X... I cannot find a relevant source kind, but program should not be here...")
386
457
  sys.exit(1)
387
458
  if (url is not None) and is_int(url) and int(url) < 10:
388
- ##just preparing for the next 2
389
- #self.url = f"/dev/video{url}"
390
- ##self.device = f"/dev/video{url}"
391
- ##self.internet_not_device = False
392
- ##self.post_addr = None #self.url.replace("/video", "/cross")
393
- print("X... should enver get here")
459
+ print("X... should never get here")
394
460
  sys.exit(1)
461
+ #--------------------- decide if device or internet http:// ----
395
462
  if (url is not None) and url.find("/dev/video") >= 0:
396
463
  self.device = url
397
464
  self.url = url#"local"
398
- self.internet_not_device = False # override
465
+ self.internet_not_device = False #
399
466
  self.post_addr = None# self.url.replace("/video", "/cross")
400
467
  if not os.path.exists( self.device):
401
468
  print(f"i... {self.device} DOES NOT exists ")
402
- elif (url is not None) and url.find("http://") >= 0:
469
+ elif (url is not None) and (url.find("http://") or url.find("http://")) >= 0:
403
470
  self.url = url
404
- self.internet_not_device = True
471
+ self.internet_not_device = True #
405
472
  self.post_addr = self.url.replace("/video", "/cross")
473
+
474
+ elif (url is not None) and url.find("mqtt://") >= 0:
475
+ ipdeco = url.split("mqtt://")[-1] # remove protocol
476
+ self.url = ipdeco.split("/")[0] # jsut IP address for mqtt
477
+ self.mqtt_topic = ipdeco.split("/")[1:] # IP address
478
+ self.mqtt_topic = "/".join(self.mqtt_topic)
479
+ self.internet_not_device = True #
480
+ self.internet_mqtt = True #
481
+ self.post_addr = None#self.url.replace("/video", "/cross")
406
482
  else:
407
483
  print(f"X... {self.url} x {self.device} ")
484
+ #---------------------------------------------------------------
408
485
  self.resolution = resolution
409
486
  self.fourcc = fourcc
410
487
  #self.internet_not_device = internet_not_device
@@ -431,7 +508,7 @@ class StreamWidget(QLabel):
431
508
  self.bytex = b"" # stream
432
509
  # ----------------------------------- initial frame -------------- was always STRIPS, now NONE: helsp w VCR ----
433
510
  # with big colored strips
434
- self.frame = None#np.zeros((self.height, self.width, 3), dtype=np.uint8)
511
+ self.frame = None # do COPY() to img # np.zeros((self.height, self.width, 3), dtype=np.uint8)
435
512
  self.which_error = "" # no error, can be url http...
436
513
  self.frames_to_fail_max = 5 # countdown to 0 and reset CAP
437
514
  self.frames_to_fail = self.frames_to_fail_max # countdown to 0 and reset CAP
@@ -879,6 +956,8 @@ class StreamWidget(QLabel):
879
956
  # ---------------------------
880
957
  if selfimg is None:
881
958
  return
959
+
960
+ #print(f"D... overtext {self.img.shape} ")
882
961
  RXT = f"XT:{self.r_xtend}" # CC LU ... for remote ok
883
962
  ZOO = f"ZOO:{self.zoomme:3.1f}"
884
963
  ROO = f"ROT:{self.l_rotate:3.1f}"
@@ -896,15 +975,29 @@ class StreamWidget(QLabel):
896
975
  total_size = sys.getsizeof(self.FABuffer)
897
976
  cur_size = len(self.FABuffer)
898
977
  max_size = self.FABuffer.get_max_frames()
978
+ total_size = sys.getsizeof(selfimg) * cur_size
899
979
 
900
980
  #if self.accum_buffer is not None:
901
981
  # total_size = sys.getsizeof(self.accum_buffer) + sum(sys.getsizeof(arr) for arr in self.accum_buffer)
902
982
  #BUF = f"BUF={self.accum_count:3d}/{self.accum_n:3d} {total_size/1024/1024:5.0f} MB"
903
- BUF = f"BUF={cur_size:3d}/{max_size:3d} {total_size/1024/1024:5.0f} MB"
904
- #
983
+ bufshow = "( )"
984
+ if self.l_show_accum:
985
+ if self.l_show_accum_avg:
986
+ bufshow = "(AVG)"
987
+ else:
988
+ bufshow = "(SUM)"
989
+ else:
990
+ bufshow = "( )"
991
+
992
+ BUF = f"BUF{bufshow}={cur_size:3d}/{max_size:3d} {total_size/1024/1024:5.0f} MB"
905
993
  #
994
+ #*********************************** HERE I CONTRUCT THE BOTTOM LINE ***********************
906
995
  #
907
- overtext = f"{self.frame_time} # {self.frame_num} # {self.l_frame_num:6d} # {RXT} . {ZOO} . {ROO} . {LGA} . {SAV} {FIT} . {BUF}. {LAPS}"
996
+ #overtext = f"{self.frame_time} # {self.frame_num} # {self.l_frame_num:6d} # {RXT} . {ZOO} . {ROO} . {LGA} . {SAV} {FIT} . {BUF}. {LAPS}"
997
+ # SAVING is already red
998
+ overtext = f"{self.frame_time} # {self.frame_num} # {self.l_frame_num:6d} # {RXT} . {ZOO} . {ROO} . {LGA} . {FIT} . {BUF}. {LAPS}"
999
+ # ROTATE IS LOCAL
1000
+ overtext = f"{self.frame_time} # {self.frame_num} # {self.l_frame_num:6d} # {RXT} . {ZOO} . {LGA} . {FIT} . {BUF}. {LAPS}"
908
1001
  #
909
1002
  position = ( 0, selfimg.shape[0]-1 ) # 480 on x-axis
910
1003
  #
@@ -930,7 +1023,7 @@ class StreamWidget(QLabel):
930
1023
  position = ( selfimg.shape[1] - 20, selfimg.shape[0]-1 ) # 480 on x-axis
931
1024
  selfimg = iprint(selfimg, f"SAVE", font=font, position=position,color_rgb=(0,0,255) ) # bgr
932
1025
  self.img = selfimg
933
- #self.img = iprint(self.img, str(overtext), font="p7", position=position,color_rgb=(0,255,0) )
1026
+
934
1027
 
935
1028
 
936
1029
 
@@ -1117,8 +1210,11 @@ class StreamWidget(QLabel):
1117
1210
  mycnt += 1
1118
1211
  fff = fname1.replace(".jpg", f"_{mycnt:03d}.jpg")
1119
1212
  print(fff)
1213
+ # ----------------------- Overtext shoud be IMPROVED FOR DUMPED BUFFER
1120
1214
  if self.flag_print_over:
1121
- self.overtext(blackbar=True) # ---- after ACCUM ------------------ img should be tagged
1215
+ self.overtext(blackbar=True, image=i) # ---- after ACCUM ------------------ img should be tagged
1216
+ i = self.img
1217
+ print(fg.magenta, "D... simple save - overtext solved ", fg.default, end="\n")
1122
1218
  if self.saving_jpg:
1123
1219
  cv2.imwrite(fff, i, [int(cv2.IMWRITE_JPEG_QUALITY), 90])
1124
1220
  else:
@@ -1126,15 +1222,43 @@ class StreamWidget(QLabel):
1126
1222
  pass
1127
1223
  # -----------------------------------------------
1128
1224
  elif (not dumpbuffer) and (not self.l_show_accum):
1225
+ print(fg.magenta, "D... simple save overtext is there", fg.default)
1129
1226
  # This is a simple save
1130
1227
  if self.saving_jpg:
1131
1228
  cv2.imwrite(fname1, self.img, [int(cv2.IMWRITE_JPEG_QUALITY), 90])
1132
1229
  else:
1133
1230
  cv2.imwrite(fname1.replace("jpg", "png"), self.img )
1134
1231
  elif (dumpbuffer) and (self.l_show_accum):
1135
- print("D... the trickies - save every Nth-every new buffer - IDK ")
1136
- elif (not dumpbuffer) and (self.l_show_accum):
1137
- mymean = self.FABuffer.get_sum_frames()#get_mean_accum_buffer()
1232
+ # -....
1233
+ print(fg.magenta, "D... the trickies - save every Nth-every new buffer - IDK ", fg.default)
1234
+ elif (len(self.FABuffer) < 2) and (not dumpbuffer):# and (self.l_show_accum):
1235
+ # ....
1236
+ print(fg.magenta, f"D... buffer <1; cannot dump; save SUM {not self.l_show_accum_avg} or AVG {self.l_show_accum_avg}", fg.default)
1237
+ mymean = None
1238
+ if self.l_show_accum_avg: # not sum
1239
+ mymean = self.FABuffer.get_avg_frames()
1240
+ else:# # yes sum
1241
+ mymean = self.FABuffer.get_sum_frames()
1242
+ # NO OVERTEXT ! ! ! ! ! ! SOLVED
1243
+ if self.flag_print_over:
1244
+ self.overtext(blackbar=True, image=mymean)
1245
+ mymean = self.img
1246
+ if self.saving_jpg:
1247
+ cv2.imwrite(fname1, mymean, [int(cv2.IMWRITE_JPEG_QUALITY), 90])
1248
+ else:
1249
+ cv2.imwrite(fname1.replace("jpg", "png"), mymean )
1250
+ elif (len(self.FABuffer) > 1) and (not dumpbuffer):# and (self.l_show_accum):
1251
+ # ....
1252
+ print(fg.magenta, "D... buffer >1; do not dump; save SUM or AVG", fg.default)
1253
+ mymean = None
1254
+ if self.l_show_accum_avg: # not sum
1255
+ mymean = self.FABuffer.get_avg_frames()
1256
+ else:# # yes sum
1257
+ mymean = self.FABuffer.get_sum_frames()
1258
+ # NO OVERTEXT ! ! ! ! ! ! SOLVED
1259
+ if self.flag_print_over:
1260
+ self.overtext(blackbar=True, image=mymean)
1261
+ mymean = self.img
1138
1262
  if self.saving_jpg:
1139
1263
  cv2.imwrite(fname1, mymean, [int(cv2.IMWRITE_JPEG_QUALITY), 90])
1140
1264
  else:
@@ -1172,28 +1296,6 @@ class StreamWidget(QLabel):
1172
1296
  #
1173
1297
  # --------------------------------------------------
1174
1298
 
1175
- # def make_strips(self):
1176
- # """
1177
- # creates self.img and strips, increments istrip and resets it
1178
- # """
1179
- # global istrip
1180
- # width, height = 640, 480
1181
- # self.img = np.zeros((height, width, 3), dtype=np.uint8)
1182
- # strip_height = 64
1183
- # istrip += 1
1184
- # if istrip > strip_height * 2:
1185
- # istrip = 0
1186
-
1187
- # if int(istrip / strip_height) % 2== 0:
1188
- # self.img[0 :0+min(istrip, strip_height), :] = (55, 55, 0) # Red strip (BGR)
1189
- # else:
1190
- # self.img[0 :0+min(istrip, strip_height), :] = (55, 150, 0) # Red strip (BGR)
1191
- # self.img[min(istrip, strip_height):2 * strip_height, :] = (55, 55, 0) # Red strip (BGR)
1192
-
1193
- # # Draw red and green horizontal strips
1194
- # for i in range(0, height, strip_height * 2):
1195
- # self.img[i + istrip:i+strip_height+ istrip, :] = (55, 150, 0) # Red strip (BGR)
1196
- # self.img[i+strip_height+ istrip:i+ istrip+strip_height*2, :] = (55, 55, 0) # Green strip
1197
1299
 
1198
1300
 
1199
1301
  # ================================================================================
@@ -1251,7 +1353,7 @@ class StreamWidget(QLabel):
1251
1353
 
1252
1354
  def update_image(self):
1253
1355
  """
1254
- Stream Widget!!!!! self==stream technically takes img and put pixmap
1356
+ QT6 - Stream Widget!!!!! self==stream technically takes img and put pixmap
1255
1357
  """
1256
1358
 
1257
1359
  if self.rgb_image is None:return # 1st contact may no exist
@@ -1388,6 +1490,11 @@ class StreamWidget(QLabel):
1388
1490
  #cv2.waitKey(0)
1389
1491
  #cv2.destroyAllWindows()
1390
1492
 
1493
+
1494
+ # ================================================================================
1495
+ # COPY FRAME TO IMG .................
1496
+ # --------------------------------------------------------------------------------
1497
+
1391
1498
  def use_frame(self, stripes=False):
1392
1499
  """
1393
1500
  put frame on tom of img .... ONLY THIS .....
@@ -1408,7 +1515,7 @@ class StreamWidget(QLabel):
1408
1515
  # ___________________ vvv started, make gray strips _____________________________
1409
1516
  ret_val = False
1410
1517
  if True:# self.img.shape == self.frame.shape:
1411
- self.img = self.frame
1518
+ self.img = self.frame.copy()
1412
1519
  if stripes: # These are thin gray
1413
1520
  #self.vcr_pal_style(["NO SIGNAL"])
1414
1521
  for y in range(0, self.img.shape[0], 16):
@@ -1417,25 +1524,6 @@ class StreamWidget(QLabel):
1417
1524
  #
1418
1525
  return ret_val
1419
1526
 
1420
-
1421
- # ==================================================
1422
- # FETCHING THE IMAGE FROM VIDEODEV AND ALL LOCAL-ACTIONS ------------ ALSO INITIATING THE STREAM ------------
1423
- # --------------------------------------------------
1424
-
1425
- def fetch_and_update(self): # * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * *
1426
- """
1427
- main operation with image:: fetch_and_update + update_only
1428
- """
1429
- ret = None
1430
- #print(f".... fau : {self.internet_not_device} ")
1431
- if self.internet_not_device:
1432
- ret = self.fetch_only()
1433
- else:
1434
- #resol = "640x480"
1435
- #resol = "1920x1080"
1436
- ret = self.capture_only(self.resolution)
1437
- self.update_only(ret)
1438
-
1439
1527
  # ================================================================================
1440
1528
  # CLICK TRICK to recover resolution in CLI
1441
1529
  # --------------------------------------------------------------------------------
@@ -1495,16 +1583,18 @@ class StreamWidget(QLabel):
1495
1583
  if not ret:
1496
1584
  return False
1497
1585
  print(f" ... {self.frame_time} ; resolution /{self.frame.shape}/ .... ", end="")
1498
-
1499
- avg = self.frame # once per Nx it is AVG
1500
- self.img = avg # normally frame. but sometimes avg == really averaged img!
1586
+ # ADD ONE FRAME !!!!!!!!
1587
+ self.l_frame_num += 1
1588
+ #avg = self.frame # once per Nx it is AVG
1589
+ #self.img = avg # normally frame. but sometimes avg == really averaged img!
1590
+ self.img = self.frame.copy()
1501
1591
  return True
1502
1592
 
1503
1593
 
1504
1594
 
1505
1595
 
1506
1596
  # ==================================================
1507
- # FETCHING THE IMAGE FROM VIDEODEV ------------ ALSO INITI
1597
+ # FETCHING THE IMAGE FROM internet VIDEODEV ------------ ALSO INITI
1508
1598
  # --------------------------------------------------
1509
1599
 
1510
1600
  def fetch_only(self):
@@ -1512,7 +1602,7 @@ class StreamWidget(QLabel):
1512
1602
  called from from fetch_and_update() / returns BOOL
1513
1603
  """
1514
1604
  ret_val = False
1515
- if self.stream is None:
1605
+ if self.stream is None: # INITIALIZE THE STREAM -----------------
1516
1606
  #self.make_strips()
1517
1607
  self.stream = self.get_stream(videodev=self.url)
1518
1608
  if self.stream is not None:
@@ -1543,6 +1633,7 @@ class StreamWidget(QLabel):
1543
1633
  self.t_lasread = self.l_frame_time
1544
1634
  self.l_frame_time = dt.datetime.now()
1545
1635
  delta_frame = (self.l_frame_time - self.t_lasread).total_seconds() # TOTAL
1636
+ self.l_frame_num += 1 # INCREMENT LOCAL FRAME NUMBER
1546
1637
  #
1547
1638
  print(f" ; {self.stream_length/delta_frame/1024/1024*8:4.2f} Mbs .. buffer tot= {len(self.bytex)/1024:4.1f} kB; Reading:{delta_read:4.2f} s.; TOT {str(delta_frame)[:4]} s.; Duty {int((delta_frame-delta_read)/delta_frame*100):3.0f} % ", end="")
1548
1639
  #
@@ -1603,6 +1694,178 @@ class StreamWidget(QLabel):
1603
1694
  return ret_val
1604
1695
 
1605
1696
 
1697
+
1698
+ # ==================================================
1699
+ # FETCHING THE IMAGE FROM ------------ MQTT
1700
+ # --------------------------------------------------
1701
+
1702
+
1703
+
1704
+ def decode_payload(self, data):
1705
+ """
1706
+ MUST BE SAME AS SENDER
1707
+ """
1708
+ header_size = struct.calcsize('!HHQddIfff') # SAME CODE 2x
1709
+ width, height, framenumber, timestamp_ts, recording_started_ts, _, exposition, gain, gamma = struct.unpack('!HHQddIfff', data[:header_size])
1710
+ image = np.frombuffer(data[header_size:], dtype=np.uint8).reshape((height, width, 3))
1711
+ timestamp = dt.datetime.fromtimestamp(timestamp_ts)
1712
+ recording_started = dt.datetime.fromtimestamp(recording_started_ts)
1713
+ return {
1714
+ 'width': width,
1715
+ 'height': height,
1716
+ 'framenumber': framenumber,
1717
+ 'timestamp': timestamp,
1718
+ 'recording_started': recording_started,
1719
+ 'exposition': exposition,
1720
+ 'gain': gain,
1721
+ 'gamma': gamma,
1722
+ 'image': image
1723
+ }
1724
+
1725
+
1726
+ def on_message(self, client, userdata, msg):
1727
+ """
1728
+ just copy content to frame and set flag
1729
+ """
1730
+ data = msg.payload
1731
+ #width, height = struct.unpack('!HH', data[:4])
1732
+ #image = np.frombuffer(data[4:], dtype=np.uint8).reshape((height, width, 3))
1733
+ #####image = np.frombuffer(data, dtype=np.uint8).reshape((480, 640, 3))
1734
+ data_block = self.decode_payload(data)
1735
+ self.frame_num = data_block['framenumber']
1736
+ self.frame_time = str(data_block['timestamp'])[:-4]
1737
+ #print(f"i... mqtt image: shape={image.shape} time={dt.datetime.now()}", end="\r" )
1738
+ self.frame = data_block['image'].copy()
1739
+ self.mqtt_new_image = True
1740
+ #print( flush=True)
1741
+ #cv2.imshow("Received Image", image)
1742
+ #cv2.waitKey(10) # Needed to refresh window
1743
+
1744
+ def subscribe_only(self):
1745
+ """
1746
+ called from from fetch_and_update() / returns BOOL / I want to read image via mqtt 1883
1747
+ """
1748
+ if not self.mqtt_subscribed:
1749
+ #self.mqtt_broker = "10.10.104.17"
1750
+ #self.mqtt_topic = "image/raw"
1751
+
1752
+ self.mqtt_client = mqtt.Client()
1753
+ self.mqtt_client.on_message = self.on_message
1754
+
1755
+ self.mqtt_client.connect(self.url, 1883, 60) # 60 seconds?
1756
+ self.mqtt_client.subscribe(self.mqtt_topic)
1757
+ print("i... ... looping inside thread... on_message active")
1758
+ self.mqtt_subscribed = True
1759
+ # Start loop in a separate thread to handle network traffic
1760
+ thread = threading.Thread(target=self.mqtt_client.loop_start)
1761
+ thread.daemon = True
1762
+ thread.start()
1763
+ #self.mqtt_client.loop_forever()
1764
+
1765
+ else:# ==================== it is subscribed =========================
1766
+ # just loop-wait for a new image
1767
+ #while True:
1768
+ #print(self.mqtt_new_image)
1769
+ if self.mqtt_new_image: # ALL ACTION HERE - use_frame; franum++ ....
1770
+ self.mqtt_new_image = False
1771
+ self.use_frame() # i copy grame
1772
+ self.l_frame_num += 1
1773
+ self.error = False
1774
+ else:
1775
+ time.sleep(0.02)
1776
+ # return False
1777
+ #break
1778
+ #time.sleep(0.1)
1779
+ return True
1780
+
1781
+
1782
+
1783
+ # ==================================================
1784
+ # FETCHING THE IMAGE FROM VIDEODEV AND ALL LOCAL-ACTIONS ------------ ALSO INITIATING THE STREAM ------------
1785
+ #
1786
+ # I think the main function here is fetch_and_update #
1787
+ # - when IP, it does fetch, when not, it grabs image.
1788
+ # -
1789
+ #
1790
+ # --------------------------------------------------
1791
+
1792
+ def fetch_and_update(self): # * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * *
1793
+ """
1794
+ main operation with image:: fetch_and_update + update_only
1795
+ """
1796
+ ret = None
1797
+ #print(f".... fau : {self.internet_not_device} ")
1798
+ if self.internet_not_device:
1799
+ if self.internet_mqtt:
1800
+ ret = self.subscribe_only() # MQTT
1801
+ else:
1802
+ ret = self.fetch_only() # just normaly fetch
1803
+ else:
1804
+ #resol = "640x480"
1805
+ #resol = "1920x1080"
1806
+ ret = self.capture_only(self.resolution)
1807
+ self.update_only(ret)
1808
+
1809
+
1810
+ # #!/usr/bin/env python3
1811
+ # import struct
1812
+ # import paho.mqtt.client as mqtt
1813
+ # import numpy as np
1814
+ # import datetime as dt
1815
+ # import time
1816
+
1817
+ # def provide(width, height):
1818
+ # # Create colorful structured image with gradients and sinusoidal patterns
1819
+
1820
+ # x = np.linspace(0, 4 * np.pi, width)
1821
+ # y = np.linspace(0, 4 * np.pi, height)
1822
+ # X, Y = np.meshgrid(x, y)
1823
+ # r = ((np.sin(X) + 1) * 127).astype(np.uint8)
1824
+ # g = ((np.cos(Y) + 1) * 127).astype(np.uint8)
1825
+ # b = ((np.sin(X + Y) + 1) * 127).astype(np.uint8)
1826
+
1827
+ # # Randomize grid frequency and color amplitude
1828
+ # freq_x = np.random.uniform(2, 6)
1829
+ # freq_y = np.random.uniform(2, 6)
1830
+ # amp = np.random.uniform(80, 150)
1831
+ # x = np.linspace(0, freq_x * np.pi, width)
1832
+ # y = np.linspace(0, freq_y * np.pi, height)
1833
+ # X, Y = np.meshgrid(x, y)
1834
+ # r = ((np.sin(X) + 1) * amp / 2).clip(0, 255).astype(np.uint8 )
1835
+ # g = ((np.cos(Y) + 1) * amp / 2).clip(0, 255).astype(np.uint8)
1836
+ # b = ((np.sin(X + Y) + 1) * amp / 2).clip(0, 255).astype(np.uint8)
1837
+ # image = np.stack((r, g, b), axis=2)
1838
+ # # Add random noise element
1839
+ # #noise = np.random.randint(0, 50, (height, width, 3), dtype=np.uint8)
1840
+ # #image = np.clip(image + noise, 0, 255).astype(np.uint8)
1841
+ # return image
1842
+
1843
+ # broker = "127.0.0.1"
1844
+ # topic = "image/raw"
1845
+
1846
+ # client = mqtt.Client()
1847
+ # client.connect(broker, 1883, 10)
1848
+
1849
+ # for i in range(100):
1850
+
1851
+ # # Create dummy image
1852
+ # #image = np.random.randint(0, 256, (480, 640, 3), dtype=np.uint8)
1853
+ # height,width=1080,1920
1854
+ # height,width=480,640
1855
+ # header = struct.pack('!HH', width, height) # Network byte order
1856
+ # #image = np.random.randint(0, 256, (height, width, 3), dtype=np.uint8)
1857
+ # image=provide(width, height)
1858
+ # payload = header + image.tobytes()
1859
+ # # Send raw bytes
1860
+ # print(dt.datetime.now())
1861
+ # result=client.publish(topic, payload )
1862
+ # print(dt.datetime.now())
1863
+ # #result.wait_for_publish() # Ensure message is sent before continuing
1864
+ # #print(dt.datetime.now())
1865
+ # time.sleep(0.96)
1866
+
1867
+ # client.disconnect()
1868
+
1606
1869
  ##################################################################
1607
1870
  # # m mmmm mm m m #
1608
1871
  # m m mmmm mmm# mmm mm#mm mmm m" "m #"m # # #
@@ -1615,8 +1878,6 @@ class StreamWidget(QLabel):
1615
1878
 
1616
1879
 
1617
1880
 
1618
-
1619
-
1620
1881
  # ================================================================================
1621
1882
  # All the traNSFORMS and saves are here
1622
1883
  # --------------------------------------------------------------------------------
@@ -1630,9 +1891,10 @@ class StreamWidget(QLabel):
1630
1891
  # ___________________________ after this point - NO REFERENCE TO FRAME ***** only img *********************
1631
1892
  # ___________________________________ whatever, RET VAL ------------RET VAL ------------RET VAL ------------
1632
1893
  if ret_val and not self.error: # OK
1894
+ # IMG SHOULD BE HERE READY!!!!!!!!!!!!
1633
1895
 
1634
- self.l_frame_num += 1
1635
- #print(self.l_frame_num)
1896
+ #self.l_frame_num += 1 # NOT GOOD!!!!!!!!!!!!!!!
1897
+ #print("D... ... franum", self.l_frame_num)
1636
1898
 
1637
1899
  # ------------------------- calculate bias to see lost frames count ----------------------
1638
1900
  # no change to frame
@@ -1686,8 +1948,8 @@ class StreamWidget(QLabel):
1686
1948
  rimg = self.FABuffer.get_avg_frames()#_mean_accum_buffer()
1687
1949
  else:
1688
1950
  rimg = self.FABuffer.get_sum_frames()#_mean_accum_buffer()
1689
- #print("\n new", type(rimg))
1690
- print(f"SATURATED: {self.FABuffer.get_saturated_pixel_count()}", end="")
1951
+ #print("\n new", type(rimg))
1952
+ print(f"SATURATED: {self.FABuffer.get_saturated_pixel_count()}", end="") # only for SUM
1691
1953
  else:
1692
1954
  rimg = self.FABuffer.get_previous_sum_frames()#_mean_accum_buffer()
1693
1955
  #print("\n----pre", type(rimg))
@@ -1730,92 +1992,129 @@ class StreamWidget(QLabel):
1730
1992
 
1731
1993
  # ---- just save once -------------------- ************ "s" ***********
1732
1994
  if self.saving_once:
1733
- # jpg and NO AVG
1995
+ # jpg and NO AVG --------- No difference show_accum_not_showaccum if frabuffer ==1
1734
1996
  if (len(self.FABuffer) < 2) and (not self.l_show_accum) and (not self.saving_fits_only):
1735
1997
  # no bufffer no loopshow no fits
1998
+ print(f"\ni... {fg.red}SAVING ONE 1 B1 NOshac{fg.default}")
1999
+ self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=False ) # one simple image
2000
+ #print(fg.magenta, "\ns1 b1 shac", fg.default, end="\n")
2001
+ self.saving_once = False
2002
+ elif (len(self.FABuffer) < 2) and (self.l_show_accum) and (not self.saving_fits_only):
2003
+ # no bufffer no loopshow no fits
2004
+ print()
2005
+ print(f"i... {fg.red}SAVING ONE 2 B1 shac{fg.default}")
1736
2006
  self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=False ) # one simple image
1737
- print(fg.red, "s1", fg.default, end="")
2007
+ #print(fg.red, "\ns1", fg.default, end="\n")
1738
2008
  self.saving_once = False
1739
2009
  # jpg and NO AVG
1740
2010
  elif (len(self.FABuffer) >= 2) and (not self.l_show_accum) and (not self.saving_fits_only):
2011
+ print()
2012
+ print(fg.red, "SAVING ONE 3 B2+ NOshac ", fg.default, end="\n")
1741
2013
  self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False ) # save one simple image only
1742
- print(fg.red, "s1", fg.default, end="")
1743
2014
  self.saving_once = False
1744
2015
  # jpg and AVG
1745
2016
  elif (len(self.FABuffer) < 2) and (self.l_show_accum) and (not self.saving_fits_only):
1746
2017
  # no bufffer no loopshow no fits
2018
+ print()
2019
+ print(fg.red, "SAVING ONE 4 B1 shac ", fg.default, end="\n")
1747
2020
  self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False ) # just one simple image /lshow inside
1748
- print(fg.red, "F1", fg.default, end="")
2021
+ #print(fg.red, "F1", fg.default, end="")
1749
2022
  self.saving_once = False
1750
2023
  pass
1751
2024
  # jpg and AVG
1752
2025
  elif (len(self.FABuffer) >= 2) and (self.l_show_accum) and (not self.saving_fits_only):
1753
2026
  # no bufffer no loopshow no fits
1754
2027
  #if self.accum_index >= len(self.FABuffer) - 1:
2028
+ print()
2029
+ print(fg.red, "SAVING ONE 5 B2+ shac ", fg.default, end="\n")
1755
2030
  self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False ) # should be 1 AVG IMG
1756
- print(fg.red, "F1", fg.default, end="")
2031
+ #print(fg.red, "F1", fg.default, end="")
1757
2032
  self.saving_once = False
1758
2033
  # FITS and NO AVG ---------------------------------------------------------------------------- FITS
1759
2034
  elif (len(self.FABuffer) < 2) and (not self.l_show_accum) and (self.saving_fits_only):
1760
2035
  # no bufffer no loopshow YES fits
2036
+ print()
2037
+ print(fg.red, "SAVING ONE 6 B1 NOshac ", fg.default, end="\n")
1761
2038
  self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=True ) # 1 img
1762
- print(fg.red, "F1", fg.default, end="")
2039
+ #print(fg.red, "F1", fg.default, end="")
1763
2040
  self.saving_once = False
1764
2041
  pass
1765
2042
  # FITS and NO AVG
1766
2043
  elif (len(self.FABuffer) >= 2) and (not self.l_show_accum) and (self.saving_fits_only):
1767
2044
  # no bufffer no loopshow no fits
2045
+ print(fg.red, "SAVING ONE 7 B2 NOshac ", fg.default, end="\n")
1768
2046
  self.save_img( time_tag=self.frame_time , dumpbuffer=True, use_fits=True ) # dump buffer once
1769
- print(fg.red, "F1", fg.default, end="")
2047
+ #print(fg.red, "F1", fg.default, end="")
1770
2048
  self.saving_once = False
1771
2049
  pass
1772
2050
  # FITS and avg
1773
2051
  elif (len(self.FABuffer) < 2) and (self.l_show_accum) and (self.saving_fits_only):
1774
2052
  # no bufffer no loopshow no fits
2053
+ print()
2054
+ print(fg.red, "SAVING ONE 8 B1 shac ", fg.default, end="\n")
1775
2055
  self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=True ) # one AVG
1776
- print(fg.red, "F1", fg.default, end="")
2056
+ #print(fg.red, "F1", fg.default, end="")
1777
2057
  self.saving_once = False
1778
2058
  pass
1779
2059
  # FITS and avg there are more
1780
2060
  elif (len(self.FABuffer) >= 2) and (self.l_show_accum) and (self.saving_fits_only):
1781
2061
  # no bufffer no loopshow no fits
1782
2062
  #if self.accum_index >= len(self.FABuffer) - 1:
2063
+ print()
2064
+ print(fg.red, "SAVING ONE 9 B2+ shac ", fg.default, end="\n")
1783
2065
  self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=True ) # many AVG IDK
1784
- print(fg.red, "F1", fg.default, end="")
2066
+ #print(fg.red, "F1", fg.default, end="")
1785
2067
  self.saving_once = False
1786
2068
 
1787
2069
 
1788
2070
  # ---- save ALL ----------------- -------------------------------------------- ************ "shift-s" ***********
1789
2071
  # ---- save ALL ----------------- -------------------------------------------- ************ "shift-s" ***********
1790
- if self.saving_all: # --------------- Shift-S-------
2072
+ if self.saving_all: # --------------- Shift-S------- ALWAYS PUT RED
1791
2073
 
1792
- # jpg and NO AVG
1793
- if (len(self.FABuffer) < 2) and (not self.l_show_accum) and (not self.saving_fits_only):
2074
+ # jpg and NO AVG when no frbuffer, showaccum makes no sense
2075
+ if (len(self.FABuffer) < 2) and (not self.l_show_accum) and (not self.saving_fits_only):
2076
+ print()
2077
+ print(fg.red, "D... SALL 1 B1 NOshaccum NOdump", fg.default, f"{bg.red}{fg.white}!!ALL-1!!{bg.default}{fg.default}", end="\n")
2078
+ self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False) # every frame, BURSTING JPGS!
2079
+ elif (len(self.FABuffer) < 2) and (self.l_show_accum) and (not self.saving_fits_only):
2080
+ print()
2081
+ print(fg.red, "D... SALL 2 B1 shaccum NOdump", fg.default, f"{bg.red}{fg.white}!!ALL-2!!{bg.default}{fg.default}", end="\n")
1794
2082
  self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False) # every frame, BURSTING JPGS!
1795
- print(fg.red, "s!", fg.default, f"{bg.red}{fg.white}!!!!!!!!!!!!{bg.default}{fg.default}", end="\n")
1796
2083
  # jpg and NO AVG
1797
2084
  elif (len(self.FABuffer) >= 2) and (not self.l_show_accum) and (not self.saving_fits_only):
2085
+ print()
2086
+ print(fg.red, "D... SALL 3 B2+ NOshac DUMP", fg.default, end="\n") # ONE DUMP
1798
2087
  self.save_img( time_tag=self.frame_time, dumpbuffer=True, use_fits=False ) # Dump Full Buffer and stop
1799
- print(fg.red, "s-FuB DUMPED", fg.default, end="\n") # ONE DUMP
1800
2088
  self.saving_all = False
1801
2089
  # jpg and AVG
1802
2090
  elif (len(self.FABuffer) < 2) and (self.l_show_accum) and (not self.saving_fits_only):
1803
2091
  # no bufffer no loopshow no fits
1804
2092
  #self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False ) # just one simple image /lshow inside
2093
+ print()
2094
+ print(fg.red, "D... SALL 4 B1 shaccum / switching OFF saving all but not saving", fg.default, end="\n") # ???
1805
2095
  self.saving_all = False
1806
2096
  pass
1807
2097
  # jpg and AVG
1808
- elif (len(self.FABuffer) >= 2) and (self.l_show_accum) and (not self.saving_fits_only):
2098
+ elif (len(self.FABuffer) >= 2) and (self.l_show_accum) and (not self.saving_fits_only): # ??? newSUM x newAVG
2099
+ #
2100
+ #if self.l_show_accum_avg:
2101
+ # rimg = self.FABuffer.get_avg_frames()#_mean_accum_buffer()
2102
+ #
1809
2103
  # no bufffer no loopshow no fits
1810
2104
  #self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False ) # should be AVG
1811
2105
  #if self.accum_index >= len(self.FABuffer) - 1:
1812
2106
  if self.FABuffer.new_sum_available():
2107
+ print()
2108
+ if self.l_show_accum_avg:
2109
+ print(fg.red, "D... SALL 5a shac Save AVG evry Nth ", fg.default, end="\n")
2110
+ else:
2111
+ print(fg.red, "D... SALL 5b Save SUM evry Nth ", fg.default, end="\n")
1813
2112
  self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=False ) # Dump Full Buffer and stop
1814
- print(fg.red, "Save SUM evry Nth ", fg.default, end="\n")
1815
2113
  # FITS and NO AVG ---------------------------------------------------------------------------- FITS
1816
2114
  # FITS and NO AVG ---------------------------------------------------------------------------- FITS
1817
2115
  elif (len(self.FABuffer) < 2) and (not self.l_show_accum) and (self.saving_fits_only):
1818
- print(" here fits for every image .... too low buffer --- so MAYBE ")
2116
+ print(fg.red, "D... SALL 6 fits for every image ... ", fg.default, end="\n")
2117
+ #print(" here fits for every image .... too low buffer --- so MAYBE ")
1819
2118
  # no bufffer no loopshow YES fits
1820
2119
  self.save_img( time_tag=self.frame_time, dumpbuffer=False, use_fits=True) # every frame, BURSTING FITS !?!?!
1821
2120
  #print(fg.red, "every N frames to FITS-IDK", fg.default, f"{bg.red}{fg.white}???{bg.default}{fg.default}", end="\n")
@@ -1843,8 +2142,8 @@ class StreamWidget(QLabel):
1843
2142
  #self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=True ) # many AVG IDK
1844
2143
  if self.FABuffer.new_sum_available():
1845
2144
  #if self.accum_index >= len(self.FABuffer) - 1: # ONLY THE ACCUM FRAME!
1846
- self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=True ) # SIMPLIFIED
1847
2145
  print(fg.red, "F-Every Nth-AVG to FITS -IDK", fg.default, end="")
2146
+ self.save_img( time_tag=self.frame_time , dumpbuffer=False, use_fits=True ) # SIMPLIFIED
1848
2147
  ###########################################################################################################################################
1849
2148
  # if self.level2_buffer.get_frame_shape() != self.img.shape: #
1850
2149
  # print(self.level2_buffer.get_frame_shape, self.img.shape) # CLEAR WHEN RES_CHANGE #
@@ -1878,6 +2177,7 @@ class StreamWidget(QLabel):
1878
2177
 
1879
2178
  #
1880
2179
  else:# --- NO IMAGE CREATED ------------------------------- ... make the image gray ...
2180
+ print(f" ret_val {ret_val} ... self.error {self.error} ")
1881
2181
  #print("D... 3")
1882
2182
  # Extra override with some frame
1883
2183
  self.img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
@@ -1937,7 +2237,9 @@ class StreamWidget(QLabel):
1937
2237
  #post_addr = self.url.replace("/video", "/cross") # FOR REMOTE COMMANDS
1938
2238
 
1939
2239
  #print(" + ".join(parts), f" /{chr(key)}/ .... {parts_set}")
1940
- # ----------------------------------------------------------------- s savings
2240
+
2241
+
2242
+ # ----------------------------------------------------------------- s savings - LOCAL ONLY !
1941
2243
  if (key == Qt.Key.Key_S):
1942
2244
  self.SAVED_NOW = True # red blink
1943
2245
  if ( len(parts_set) == 0) :
@@ -1945,12 +2247,12 @@ class StreamWidget(QLabel):
1945
2247
  self.saving_all = False
1946
2248
  #self.saving_fits_only = False
1947
2249
  #self.saving_jpg = True
1948
- print("i... SAVING_ONCE IMAGE ")
2250
+ #print(f"i... {fg.red}SAVING_ONCE IMAGE {fg.default}")
1949
2251
  #---------------- SHIFT-S: 1) IbufferON=> save every nth image; 2) ---
1950
2252
  elif (parts_set == {'Shift'}):
1951
2253
  self.saving_all = not self.saving_all
1952
2254
  #self.saving_fits_only = False
1953
- print(f"i... 'SAVING_all' SET TO {self.saving_all} !!!!!FITS=={self.saving_fits_only}!!!!! ")
2255
+ print(f"i... {fg.orange}'SAVING_all' SET TO {self.saving_all} !!!!!FITS=={self.saving_fits_only}!!!!! {fg.default}")
1954
2256
  if self.saving_all:
1955
2257
  print('ffmpeg -framerate 5 -pattern_type glob -i "*.jpg" -c:v libx264 -pix_fmt yuv420p output.mkv')
1956
2258
  print('ffmpeg -hide_banner -y -framerate 5 -pattern_type glob -i "*.jpg" -c:v libx264 -pix_fmt yuv420p output.mkv')
@@ -1973,7 +2275,7 @@ class StreamWidget(QLabel):
1973
2275
  else:
1974
2276
  print(f"i... {fg.orange}PNG!{fg.default} SAVING_JPG set to {fg.cyan}{self.saving_jpg}{fg.default} (interval is {self.FITS_INTERVAL_SECONDS}) ; but 'SAVING_all' SET TO ", self.saving_all)
1975
2277
 
1976
- # ----------------------------------------------------------------- x xtend x2 ot switchres resolution
2278
+ # ------------------------------ xtend x2 ot switchres resolution--- x XRES SWITCH - REMOTE - **SEND_COMMAND**
1977
2279
  if (key == Qt.Key.Key_X):
1978
2280
  if ( len(parts_set) == 0):
1979
2281
  self.xtended = not self.xtended
@@ -1991,7 +2293,7 @@ class StreamWidget(QLabel):
1991
2293
  self.send_command( data={"switch_res_off": "SWITCH_RES_OFF"})
1992
2294
  print("D.... r_xtend == ' ' <<======== ", self.r_xtend)
1993
2295
 
1994
- # ----------------------------------------------------------------- p printout
2296
+ # ----------------------------------------------------------------- p printout - LOCAL ONLY
1995
2297
  if (key == Qt.Key.Key_P):
1996
2298
  if ( len(parts_set) == 0):
1997
2299
  self.flag_print = not self.flag_print
@@ -2002,7 +2304,7 @@ class StreamWidget(QLabel):
2002
2304
  print(f"i... overtext: {self.flag_print_over}")
2003
2305
  elif (parts_set == {'Ctrl'}) :
2004
2306
  pass
2005
- # ----------------------------------------------------------------- e expo
2307
+ # ----------------------------------------------------------------- e expo - REMOTE ONLY ! **SEND_COMMAND**
2006
2308
  if (key == Qt.Key.Key_E):
2007
2309
  if ( len(parts_set) == 0):
2008
2310
  if self.r_expo < 1.0: self.r_expo += 0.02
@@ -2018,7 +2320,7 @@ class StreamWidget(QLabel):
2018
2320
  self.send_command( data= {"expot": "EXPOT", "expotxt": -1.0} )
2019
2321
  self.r_expodef = True
2020
2322
 
2021
- # ----------------------------------------------------------------- g gain
2323
+ # ----------------------------------------------------------------- g gain - REMOTE ONLY ! **SEND_COMMAND**
2022
2324
  if (key == Qt.Key.Key_G):
2023
2325
  if ( len(parts_set) == 0):
2024
2326
  if self.r_gain < 1.0: self.r_gain += 0.1
@@ -2038,7 +2340,7 @@ class StreamWidget(QLabel):
2038
2340
  # self.send_command( data= {"gain05": "GAIN05"})
2039
2341
  #elif (parts_set == {'Ctrl'}) :
2040
2342
  # self.send_command( data= {"gain": "GAIN"} )
2041
- # ----------------------------------------------------------------- y gamma
2343
+ # ----------------------------------------------------------------- y gamma - REMOTE ONLY ! **SEND_COMMAND**
2042
2344
  if (key == Qt.Key.Key_Y):
2043
2345
  if ( len(parts_set) == 0):
2044
2346
  if self.r_gamma < 1.0: self.r_gamma += 0.1
@@ -2059,7 +2361,7 @@ class StreamWidget(QLabel):
2059
2361
  # self.send_command( data= {"gamma05": "GAMMA05"})
2060
2362
  #elif (parts_set == {'Ctrl'}) :
2061
2363
  # self.send_command( data= {"gamma": "GAMMA"} )
2062
- # ----------------------------------------------------------------- d local gamma
2364
+ # ----------------------------------------------------------------- d local gamma - LOCAL ONLY
2063
2365
  if (key == Qt.Key.Key_D):
2064
2366
  if ( len(parts_set) == 0):
2065
2367
  self.l_gamma = self.l_gamma * 1.4
@@ -2068,7 +2370,7 @@ class StreamWidget(QLabel):
2068
2370
  elif (parts_set == {'Ctrl'}) :
2069
2371
  self.l_gamma = 1
2070
2372
 
2071
- # ----------------------------------------------------------------- w
2373
+ # ----------------------------------------------------------------- w - Web Browser - LOCAL ONLY
2072
2374
  if (key == Qt.Key.Key_W):
2073
2375
  if ( len(parts_set) == 0):
2074
2376
  webbrowser.open(self.url.replace("/video", "")) # BRUTAL
@@ -2076,7 +2378,7 @@ class StreamWidget(QLabel):
2076
2378
  pass
2077
2379
  elif (parts_set == {'Ctrl'}) :
2078
2380
  pass
2079
- # ----------------------------------------------------------------- z
2381
+ # ----------------------------------------------------------------- z - ZOOM - LOCAL ONLY !
2080
2382
  if (key == Qt.Key.Key_Z):
2081
2383
  if ( len(parts_set) == 0):
2082
2384
  self.zoomme *= 1.5
@@ -2088,7 +2390,7 @@ class StreamWidget(QLabel):
2088
2390
  if self.zoomme < 1: self.zoome= 1
2089
2391
  elif (parts_set == {'Ctrl'}) :
2090
2392
  self.zoomme = 1
2091
- # ----------------------------------------------------------------- hjkl
2393
+ # ----------------------------------------------------------------- hjkl - H - **SEND_COMMAND** c-s-*
2092
2394
  # self.send_command( data={"right": "RIGHT"})
2093
2395
  if (key == Qt.Key.Key_H):
2094
2396
  if ( len(parts_set) == 0):
@@ -2102,7 +2404,7 @@ class StreamWidget(QLabel):
2102
2404
  if self.r_xtend[0] == "R": self.r_xtend = "C" + self.r_xtend[1:]
2103
2405
  elif self.r_xtend[0] == "C": self.r_xtend = "L" + self.r_xtend[1:]
2104
2406
  elif self.r_xtend[0] == " ": self.r_xtend = "L" + self.r_xtend[1:]
2105
- # ----------------------------------------------------------------- hjkl
2407
+ # ----------------------------------------------------------------- hjkl - J **SEND_COMMAND** c-s-*
2106
2408
  if (key == Qt.Key.Key_J):
2107
2409
  if ( len(parts_set) == 0):
2108
2410
  self.redcross[1] += 4 # DOWN
@@ -2115,7 +2417,7 @@ class StreamWidget(QLabel):
2115
2417
  if self.r_xtend[1] == "U": self.r_xtend = self.r_xtend[:1] + "C"
2116
2418
  elif self.r_xtend[1] == "C": self.r_xtend = self.r_xtend[:1] + "D"
2117
2419
  elif self.r_xtend[1] == " ": self.r_xtend = self.r_xtend[:1] + "D"
2118
- # ----------------------------------------------------------------- hjkl
2420
+ # ----------------------------------------------------------------- hjkl - K **SEND_COMMAND** c-s-*
2119
2421
  if (key == Qt.Key.Key_K):
2120
2422
  if ( len(parts_set) == 0):
2121
2423
  self.redcross[1] -= 4 # UP
@@ -2128,7 +2430,7 @@ class StreamWidget(QLabel):
2128
2430
  if self.r_xtend[1] == "D": self.r_xtend = self.r_xtend[:1] + "C"
2129
2431
  elif self.r_xtend[1] == "C": self.r_xtend = self.r_xtend[:1] + "U"
2130
2432
  elif self.r_xtend[1] == " ": self.r_xtend = self.r_xtend[:1] + "U"
2131
- # ----------------------------------------------------------------- hjkl
2433
+ # ----------------------------------------------------------------- hjkl - L **SEND_COMMAND** c-s-*
2132
2434
  if (key == Qt.Key.Key_L):
2133
2435
  if ( len(parts_set) == 0):
2134
2436
  self.redcross[0] += 4
@@ -2141,7 +2443,7 @@ class StreamWidget(QLabel):
2141
2443
  if self.r_xtend[0] == "L": self.r_xtend = "C" + self.r_xtend[1:]
2142
2444
  elif self.r_xtend[0] == "C": self.r_xtend = "R" + self.r_xtend[1:]
2143
2445
  elif self.r_xtend[0] == " ": self.r_xtend = "R" + self.r_xtend[1:]
2144
- # ----------------------------------------------------------------- v GREEN CROSS
2446
+ # ----------------------------------------------------------------- v GREEN CROSS - REMOTE **SEND_COMMAND**
2145
2447
  if (key == Qt.Key.Key_V):
2146
2448
  if ( len(parts_set) == 0):
2147
2449
  self.send_command( data= {"crosson": "CROSSON"} )
@@ -2150,7 +2452,7 @@ class StreamWidget(QLabel):
2150
2452
  pass
2151
2453
  elif (parts_set == {'Ctrl'}) :
2152
2454
  self.send_command( data= {"crossoff": "CROSSOFF"} )
2153
- # ----------------------------------------------------------------- c RED CROSS
2455
+ # ----------------------------------------------------------------- c RED CROSS - LOCAL ONLY
2154
2456
  if (key == Qt.Key.Key_C):
2155
2457
  if ( len(parts_set) == 0):
2156
2458
  self.flag_redcross = True# not self.flag_redcross
@@ -2161,8 +2463,8 @@ class StreamWidget(QLabel):
2161
2463
  elif (parts_set == {'Ctrl'}) :
2162
2464
  print( "i... reset position red cross")
2163
2465
  self.redcross = [0, 0]
2164
- # ----------------------------------------------------------------- i integrate accumulate
2165
- if (key == Qt.Key.Key_I): # i shift-i Ctrl-i Ctrl-Shift-i Alt
2466
+ # ----------------------------------------------------------------- i integrate accumulate - LOCAL ONLY ! **SEND_COMMAND**
2467
+ if (key == Qt.Key.Key_I): # i:inc shift-i:dec Ctrl-i:reset Ctrl-Shift-i:watch Alt-i: SUM vs. AVG
2166
2468
  # 4.6GB / 1000 640x480
2167
2469
  if ( len(parts_set) == 0):
2168
2470
  if self.r_integrate < 8:
@@ -2190,15 +2492,17 @@ class StreamWidget(QLabel):
2190
2492
  elif (parts_set == {'Ctrl'}) :
2191
2493
  self.r_integrate = 1
2192
2494
  self.send_command( data= {"accum": "ACCUM", "accumtxt": 0})
2495
+ self.l_show_accum = False
2193
2496
  # 0 would be a problem (locally???); but 1 is not sent!!! ; SENDING 0, checking@send_command
2194
2497
  elif (parts_set == {'Ctrl', 'Shift'}) :
2498
+ # REMOVE SHOW ACCUM .... ok but I remove it also when reseting buffer
2195
2499
  self.l_show_accum = not self.l_show_accum
2196
- print(f"i... ACCUMULATION IS {self.l_show_accum}")
2500
+ print(f"i... BUFFER ACCUMULATED SHOW IS {self.l_show_accum} ; MODE AVG={self.l_show_accum_avg} MODE SUM = {not self.l_show_accum_avg}")
2197
2501
  elif (parts_set == {'Alt'}) :
2198
2502
  self.l_show_accum_avg = not self.l_show_accum_avg
2199
- print(f"i... ACCUMULATION AVG/nonSUM IS {self.l_show_accum_avg}")
2503
+ print(f"i... ACCUMULATION DISPLAY MODE SWITCHED: AVG (nonSUM) IS {self.l_show_accum_avg}")
2200
2504
 
2201
- # ----------------------------------------------------------------- b
2505
+ # ----------------------------------------------------------------- b BACKGROUND - REMOTE **SEND_COMMAND**
2202
2506
  if (key == Qt.Key.Key_B):
2203
2507
  if ( len(parts_set) == 0):
2204
2508
  self.send_command( data= {"subbg": "SUBBG"})
@@ -2206,7 +2510,7 @@ class StreamWidget(QLabel):
2206
2510
  self.send_command( data= {"savebg": "SAVEBG"})
2207
2511
  elif (parts_set == {'Ctrl'}) :
2208
2512
  pass
2209
- # ----------------------------------------------------------------- b
2513
+ # ----------------------------------------------------------------- f FOREGROUND - REMOTE **SEND_COMMAND**
2210
2514
  if (key == Qt.Key.Key_F):
2211
2515
  if ( len(parts_set) == 0):
2212
2516
  self.send_command( data= {"mixfg": "MIXFG"})
@@ -2215,7 +2519,7 @@ class StreamWidget(QLabel):
2215
2519
  elif (parts_set == {'Ctrl'}) :
2216
2520
  pass
2217
2521
 
2218
- # ----------------------------------------------------------------- r
2522
+ # ----------------------------------------------------------------- r ROTATE - LOCAL ONLY !
2219
2523
  if (key == Qt.Key.Key_R):
2220
2524
  if ( len(parts_set) == 0):
2221
2525
  self.l_rotate += 1
@@ -2223,7 +2527,7 @@ class StreamWidget(QLabel):
2223
2527
  self.l_rotate -= 1
2224
2528
  elif (parts_set == {'Ctrl'}) :
2225
2529
  self.l_rotate = 0
2226
- # ----------------------------------------------------------------- 1
2530
+ # ----------------------------------------------------------------- 1 config
2227
2531
  if (key == Qt.Key.Key_1) or (key == ord("!") ):
2228
2532
  if ( len(parts_set) == 0):
2229
2533
  print("i... config 1 - recall")
@@ -2239,7 +2543,7 @@ class StreamWidget(QLabel):
2239
2543
  print("D... r_xtend == ", self.r_xtend)
2240
2544
  elif (parts_set == {'Ctrl'}) :
2241
2545
  self.setup("q")
2242
- # ----------------------------------------------------------------- 2
2546
+ # ----------------------------------------------------------------- 2 config
2243
2547
  if (key == Qt.Key.Key_2) or (key == ord("@") ):
2244
2548
  if ( len(parts_set) == 0):
2245
2549
  print("i... config 2 - recall")
@@ -2251,7 +2555,7 @@ class StreamWidget(QLabel):
2251
2555
  self.setup("w", 2)
2252
2556
  elif (parts_set == {'Ctrl'}) :
2253
2557
  self.setup("q")
2254
- # ----------------------------------------------------------------- 3
2558
+ # ----------------------------------------------------------------- 3 config
2255
2559
  if (key == Qt.Key.Key_3) or (key == ord("#") ):
2256
2560
  if ( len(parts_set) == 0):
2257
2561
  print("i... config 3 - recall")
@@ -2263,7 +2567,7 @@ class StreamWidget(QLabel):
2263
2567
  self.setup("w", 3)
2264
2568
  elif (parts_set == {'Ctrl'}) :
2265
2569
  self.setup("q")
2266
- # ----------------------------------------------------------------- 4
2570
+ # ----------------------------------------------------------------- 4 config
2267
2571
  if (key == Qt.Key.Key_4) or (key == ord("$") ):
2268
2572
  if ( len(parts_set) == 0):
2269
2573
  print("i... config 4 - recall")
@@ -2290,7 +2594,7 @@ class StreamWidget(QLabel):
2290
2594
  elif (parts_set == {'Ctrl'}) :
2291
2595
  #self.send_command( data= {"expot": "EXPOT", "expotxt": float(-1.0)})
2292
2596
  pass
2293
- # ----------------------------------------------------------------- l tests whatever
2597
+ # ----------------------------------------------------------------- t tests whatever REMOTE ! **SEND_COMMAND**
2294
2598
  if (key == Qt.Key.Key_T):
2295
2599
  if ( len(parts_set) == 0):
2296
2600
  # THIS IS in reallity SKIPPED IN send_command ....
@@ -2333,22 +2637,15 @@ class StreamWidget(QLabel):
2333
2637
  @click.option('-r', '--resolution', default="640x480", required=False, help='Resolution value')
2334
2638
  @click.option('-f', '--fourcc', default="YUYV", required=False, help='YUYV or MJPG')
2335
2639
  def handle_cli(url, resolution, fourcc):
2640
+ """
2641
+ commandline is solved here; guess url
2642
+ """
2336
2643
  #app = QApplication() #
2337
2644
  app = QApplication(sys.argv) # NOT clear why argv here
2338
- #url = None
2339
- #if len(sys.argv)> 1:
2340
- # url = sys.argv[1]
2341
- #else:
2342
- # url = "http://127.0.0.1:8000/video"
2343
2645
  url = guess_url(url)
2344
- #if url is None:
2345
- # sys.exit(1)
2346
2646
  widget = None
2347
2647
 
2348
- #if url is None:
2349
2648
  widget = StreamWidget(url, resolution=resolution, fourcc=fourcc)
2350
- #else:
2351
- # widget = StreamWidget(url, internet_not_device=True)
2352
2649
  widget.show()
2353
2650
  sys.exit(app.exec())
2354
2651
 
pogucam/mqimr.py ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+
3
+ print("""
4
+ RECEIVE IMAGE
5
+
6
+ uv run --with paho-mqtt --with=numpy --with=opencv-python --script ./mqimr.py
7
+
8
+ show an image received from mqtt
9
+ """)
10
+
11
+
12
+ import struct
13
+ import paho.mqtt.client as mqtt
14
+ import numpy as np
15
+ import datetime as dt
16
+ import cv2
17
+
18
+ broker = "10.10.104.17"
19
+ broker = "127.0.0.1"
20
+ topic = "image/raw8000"
21
+
22
+ def decode_payload(data):
23
+ header_size = struct.calcsize('!HHQddIfff')
24
+ width, height, framenumber, timestamp_ts, recording_started_ts, _, exposition, gain, gamma = struct.unpack('!HHQddIfff', data[:header_size])
25
+ image = np.frombuffer(data[header_size:], dtype=np.uint8).reshape((height, width, 3))
26
+ timestamp = dt.datetime.fromtimestamp(timestamp_ts)
27
+ recording_started = dt.datetime.fromtimestamp(recording_started_ts)
28
+ return {
29
+ 'width': width,
30
+ 'height': height,
31
+ 'framenumber': framenumber,
32
+ 'timestamp': timestamp,
33
+ 'recording_started': recording_started,
34
+ 'exposition': exposition,
35
+ 'gain': gain,
36
+ 'gamma': gamma,
37
+ 'image': image
38
+ }
39
+
40
+
41
+ def on_message(client, userdata, msg):
42
+ data = msg.payload
43
+
44
+ data_block = decode_payload(data)
45
+ image = data_block['image']
46
+ #
47
+ #width, height = struct.unpack('!HH', data[:4])
48
+ #image = np.frombuffer(data[4:], dtype=np.uint8).reshape((height, width, 3))
49
+ #####image = np.frombuffer(data, dtype=np.uint8).reshape((480, 640, 3))
50
+ print("Received image shape:", image.shape, dt.datetime.now() )
51
+ print( flush=True)
52
+
53
+ cv2.imshow("Received Image", image)
54
+ cv2.waitKey(10) # Needed to refresh window
55
+
56
+ client = mqtt.Client()
57
+ client.on_message = on_message
58
+
59
+ client.connect(broker, 1883, 60)
60
+ client.subscribe(topic)
61
+ client.loop_forever()
pogucam/mqims.py ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+
3
+ print(""" SEND IMAGE via MQTT
4
+
5
+ uv run --with paho-mqtt --with=numpy --with=opencv-python --script ./mqims.py
6
+
7
+ """)
8
+ # connect to local MQTT
9
+ broker = "127.0.0.1"
10
+ topic = "image/raw8000"
11
+
12
+ import struct
13
+ import paho.mqtt.client as mqtt
14
+ import numpy as np
15
+ import datetime as dt
16
+ import time
17
+
18
+ def create_payload(image, framenumber, timestamp, recording_started, exposition, gain, gamma):
19
+ height, width = image.shape[:2]
20
+ header = struct.pack(
21
+ '!HHQddIfff',
22
+ width,
23
+ height,
24
+ int(framenumber),
25
+ timestamp.timestamp(),
26
+ recording_started.timestamp(),
27
+ 0, # padding for alignment if needed
28
+ float(exposition),
29
+ float(gain),
30
+ float(gamma)
31
+ )
32
+ payload = header + image.tobytes()
33
+ return payload
34
+
35
+
36
+
37
+ def provide_image(width, height):
38
+ # Add random noise element
39
+ image = np.zeros((480, 640, 3), dtype=np.uint8)
40
+ #return image # 1ms for just black
41
+ noise = np.random.randint(0, 50, (height, width, 3), dtype=np.uint8)
42
+ #image = np.clip(image + noise, 0, 255).astype(np.uint8)
43
+ #return image # 6.6ms image+noise
44
+ #---------------------------------------
45
+ # Create colorful structured image with gradients and sinusoidal patterns
46
+ x = np.linspace(0, 4 * np.pi, width)
47
+ y = np.linspace(0, 4 * np.pi, height)
48
+ X, Y = np.meshgrid(x, y)
49
+ r = ((np.sin(X) + 1) * 127).astype(np.uint8)
50
+ g = ((np.cos(Y) + 1) * 127).astype(np.uint8)
51
+ b = ((np.sin(X + Y) + 1) * 127).astype(np.uint8)
52
+
53
+ # Randomize grid frequency and color amplitude
54
+ freq_x = np.random.uniform(2, 6)
55
+ freq_y = np.random.uniform(2, 6)
56
+ amp = np.random.uniform(80, 150)
57
+ x = np.linspace(0, freq_x * np.pi, width)
58
+ y = np.linspace(0, freq_y * np.pi, height)
59
+ X, Y = np.meshgrid(x, y)
60
+ r = ((np.sin(X) + 1) * amp / 2).clip(0, 255).astype(np.uint8 )
61
+ g = ((np.cos(Y) + 1) * amp / 2).clip(0, 255).astype(np.uint8)
62
+ b = ((np.sin(X + Y) + 1) * amp / 2).clip(0, 255).astype(np.uint8)
63
+ image = np.stack((r, g, b), axis=2)
64
+ image = np.clip(image + noise, 0, 255).astype(np.uint8)
65
+ return image # alltogether 35 ms
66
+
67
+
68
+ # *********************************************************************
69
+
70
+ client = mqtt.Client()
71
+ client.connect(broker, 1883, 10)
72
+
73
+ recording_started = dt.datetime.now()
74
+ framenumber = 0
75
+ for i in range(1000):
76
+ # Create dummy image
77
+ #image = np.random.randint(0, 256, (480, 640, 3), dtype=np.uint8)
78
+ height,width=1080,1920
79
+ #
80
+ height,width=480,640
81
+ #header = struct.pack('!HH', width, height) # Network byte order
82
+ timestamp = dt.datetime.now()
83
+ framenumber += 1
84
+ #recording_started ... also timestamp
85
+ image=provide_image(width, height) # create image elsewhere
86
+ exposition, gain, gamma = 0.5, 0.5, 0.5
87
+ payload = create_payload(image, framenumber, timestamp, recording_started, exposition, gain, gamma)
88
+ #payload = header + image.tobytes()
89
+ # Send raw bytes
90
+ result=client.publish(topic, payload )
91
+ print(timestamp, end="\r")
92
+ #result.wait_for_publish() # Ensure message is sent before continuing
93
+ #print(dt.datetime.now())
94
+
95
+ #
96
+ time.sleep(0.095)
97
+
98
+ delta = dt.datetime.now() - recording_started
99
+ print(f"{delta}, {delta.total_seconds() / 1000} per frame ")
100
+ client.disconnect()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pogucam
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: Add your description here
5
5
  Author-email: jaromrax <jaromrax@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -9,6 +9,7 @@ Requires-Dist: click>=8.2.1
9
9
  Requires-Dist: console>=0.9911
10
10
  Requires-Dist: numpy>=2.3.0
11
11
  Requires-Dist: opencv-python>=4.11.0.86
12
+ Requires-Dist: paho-mqtt>=2.1.0
12
13
  Requires-Dist: pillow>=11.2.1
13
14
  Requires-Dist: pyqt6>=6.9.1
14
15
  Requires-Dist: requests>=2.32.4
@@ -0,0 +1,11 @@
1
+ pogucam/__init__.py,sha256=Iij7VvXCrFPMtTia41mQ7LxFLaulf_fD5cb-AyjpUo0,53
2
+ pogucam/buffers.py,sha256=1JLkuenkHoA-K-uZAlNV7chHQDZLrspgT5_XOY-E-34,6692
3
+ pogucam/explore_u24_uni.py,sha256=MtAQ0httaCtSBtYquD1ElXak9k7TC12v-R07kzjQroU,126592
4
+ pogucam/installation.md,sha256=8qspiLlYjEBx5CedRfBU7Mm0A2pz0lfAnaupZyBm5Eo,128
5
+ pogucam/mqimr.py,sha256=f48gTXng5vM-1RiNPXSA-IvAc3y6WMStbvfQ8rUV7l0,1727
6
+ pogucam/mqims.py,sha256=_G8AdfrbTrkIm2MOsq3tFOBYpiD4o58JUIvnZt0Sm7A,3293
7
+ pogucam/text_write.py,sha256=hyRyA1M5z-pda963T-k0i8fvvAlv1p3YBTZtYNdOeoE,19304
8
+ pogucam-0.1.14.dist-info/METADATA,sha256=-0fHR7SySxz9vmujJaNMLUUtDxILCPC_6eAoWUYzruQ,499
9
+ pogucam-0.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
+ pogucam-0.1.14.dist-info/entry_points.txt,sha256=-97N0LsXIR8h0rJMzIMuNeNwuY8LvPYPTqnXsuAnVsM,63
11
+ pogucam-0.1.14.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- pogucam/__init__.py,sha256=Iij7VvXCrFPMtTia41mQ7LxFLaulf_fD5cb-AyjpUo0,53
2
- pogucam/buffers.py,sha256=1JLkuenkHoA-K-uZAlNV7chHQDZLrspgT5_XOY-E-34,6692
3
- pogucam/explore_u24_uni.py,sha256=JY_fid_w-Trycs0plLUjv_UNLTjQW66wk4OP-nNiaTs,112075
4
- pogucam/installation.md,sha256=8qspiLlYjEBx5CedRfBU7Mm0A2pz0lfAnaupZyBm5Eo,128
5
- pogucam/text_write.py,sha256=hyRyA1M5z-pda963T-k0i8fvvAlv1p3YBTZtYNdOeoE,19304
6
- pogucam-0.1.12.dist-info/METADATA,sha256=K9zizgKKO_Ur-I4-whqe6rFG8gaBI3xVCQuYYRgl6WA,467
7
- pogucam-0.1.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
- pogucam-0.1.12.dist-info/entry_points.txt,sha256=-97N0LsXIR8h0rJMzIMuNeNwuY8LvPYPTqnXsuAnVsM,63
9
- pogucam-0.1.12.dist-info/RECORD,,