diff --git a/software/SAT0_OBC/SatImageTaking/earth.py b/software/SAT0_OBC/SatImageTaking/earth.py
index 49dbb01..7f966e6 100644
--- a/software/SAT0_OBC/SatImageTaking/earth.py
+++ b/software/SAT0_OBC/SatImageTaking/earth.py
@@ -17,21 +17,9 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
'''
-from cv2 import cvtColor as cv2_cvtColor
-from cv2 import morphologyEx as cv2_morphologyEx
-from cv2 import GaussianBlur as cv2_GaussianBlur
-from cv2 import threshold as cv2_threshold
-from cv2 import adaptiveThreshold as cv2_adaptiveThreshold
-from cv2 import bitwise_and as cv2_bitwise_and
-from cv2 import bitwise_not as cv2_bitwise_not
-from cv2 import Sobel as cv2_Sobel
-from cv2 import circle as cv2_circle
-from cv2 import findContours as cv2_findContours
-from cv2 import dilate as cv2_dilate
-from cv2 import minEnclosingCircle as cv2_minEnclosingCircle
-from cv2 import THRESH_TOZERO, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, MORPH_CLOSE, MORPH_OPEN, RETR_EXTERNAL,\
- CHAIN_APPROX_SIMPLE, COLOR_BGR2GRAY
+# 17.1.2024 asaf h: changed cv2 import cv2_ >> cv2.
+import cv2
import numpy as np
from SatImageTaking import utils
@@ -63,7 +51,7 @@ def __init__(self, path_or_image: str or np.ndarray, dim=None) -> None:
"""Constructor for earth class. Initializes the attributes of the class"""
self.mask = None
self.image = utils.get_image(path_or_image, dim=dim)
- self.gray_image = cv2_cvtColor(self.image, COLOR_BGR2GRAY)
+ self.gray_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
self.clear_sky, self.clear_earth, self.earth_mask = self.get_mask()
self.is_earth = self._is_earth()
self.earth_percent = self._earth_percent()
@@ -80,21 +68,21 @@ def _is_earth_at_night(self):
Returns:
bool: True if the image contain Earth at night, False otherwise.
"""
- gray_image = cv2_GaussianBlur(
+ gray_image = cv2.GaussianBlur(
self.gray_image, (3, 3), 0)
- _, gray_image = cv2_threshold(
- self.gray_image, 80, 255, THRESH_TOZERO)
- mask = cv2_adaptiveThreshold(
- gray_image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, blockSize=3, C=5)
+ _, gray_image = cv2.threshold(
+ self.gray_image, 80, 255, cv2.THRESH_TOZERO)
+ mask = cv2.adaptiveThreshold(
+ gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize=3, C=5)
kernel = np.ones((5, 5), np.uint8)
- mask = cv2_morphologyEx(mask, MORPH_CLOSE, kernel)
+ mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
- contours, _ = cv2_findContours(
- mask, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE)[-2:]
+ contours, _ = cv2.findContours(
+ mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
self.mask = mask
for cnt in contours:
- (x, y), r = cv2_minEnclosingCircle(cnt)
+ (x, y), r = cv2.minEnclosingCircle(cnt)
if r > 60:
return True
return False
@@ -104,17 +92,17 @@ def get_curve(self):
Returns:
np.ndarray: image that contains the curve o the Earth"""
- gauss = cv2_GaussianBlur(self.gray_image, (7, 7), 0)
+ gauss = cv2.GaussianBlur(self.gray_image, (7, 7), 0)
- _, gauss = cv2_threshold(gauss, 80, 255, THRESH_TOZERO)
+ _, gauss = cv2.threshold(gauss, 80, 255, cv2.THRESH_TOZERO)
- adaptive_mean = cv2_adaptiveThreshold(gauss, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV,
+ adaptive_mean = cv2.adaptiveThreshold(gauss, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV,
blockSize=201, C=3)
kernel = np.ones((5, 5), np.uint8)
- adaptive_mean = cv2_morphologyEx(
- adaptive_mean, MORPH_CLOSE, kernel)
- adaptive_mean = cv2_morphologyEx(
- adaptive_mean, MORPH_OPEN, kernel)
+ adaptive_mean = cv2.morphologyEx(
+ adaptive_mean, cv2.MORPH_CLOSE, kernel)
+ adaptive_mean = cv2.morphologyEx(
+ adaptive_mean, cv2.MORPH_OPEN, kernel)
return adaptive_mean
def _is_earth(self):
@@ -142,28 +130,28 @@ def _earth_percent(self):
def _get_earth_mask(self):
"""Returns the earth mask in the image"""
- gauss = cv2_GaussianBlur(self.gray_image, (5, 5), 0)
+ gauss = cv2.GaussianBlur(self.gray_image, (5, 5), 0)
- _, gray_image = cv2_threshold(
- gauss, 30, 255, THRESH_TOZERO)
+ _, gray_image = cv2.threshold(
+ gauss, 30, 255, cv2.THRESH_TOZERO)
- thresh = cv2_Sobel(src=gray_image, ddepth=-1, dx=1, dy=1, ksize=11)
+ thresh = cv2.Sobel(src=gray_image, ddepth=-1, dx=1, dy=1, ksize=11)
kernel = np.ones((10, 10), np.uint8)
- thresh = cv2_morphologyEx(thresh, MORPH_CLOSE, kernel)
+ thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((20, 20), np.uint8)
- thresh = cv2_morphologyEx(thresh, MORPH_OPEN, kernel)
+ thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = np.ones((40, 40), np.uint8)
- thresh = cv2_morphologyEx(thresh, MORPH_CLOSE, kernel)
+ thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((70, 70), np.uint8)
- thresh = cv2_morphologyEx(thresh, MORPH_OPEN, kernel)
+ thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
return thresh
def draw_black_cir(self, contours):
"""This function helps to eliminate all the stars in the sky or fill the holes in Earth mask"""
for center, radius in contours:
- cv2_circle(self.mask, center, radius, (0, 0, 0), -1)
+ cv2.circle(self.mask, center, radius, (0, 0, 0), -1)
def _get_cir_contours(self):
"""
@@ -173,11 +161,11 @@ def _get_cir_contours(self):
list: A list containing the contours of the circles in the image
"""
height, width = self.gray_image.shape
- contours, _ = cv2_findContours(
- self.mask, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE)[-2:]
+ contours, _ = cv2.findContours(
+ self.mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
all_cir = []
for cnt in contours:
- (x, y), r = cv2_minEnclosingCircle(cnt)
+ (x, y), r = cv2.minEnclosingCircle(cnt)
if r < int(max(height, width) * 0.3):
x, y, r = int(x), int(y), int(r)
center = x, y
@@ -186,10 +174,10 @@ def _get_cir_contours(self):
def fill_earth(self):
"""Fill all the little holes in Earth mask image."""
- self.mask = cv2_bitwise_not(self.mask)
+ self.mask = cv2.bitwise_not(self.mask)
contours = self._get_cir_contours()
self.draw_black_cir(contours)
- self.mask = cv2_bitwise_not(self.mask)
+ self.mask = cv2.bitwise_not(self.mask)
def get_mask(self):
"""
@@ -203,18 +191,18 @@ def get_mask(self):
self.draw_black_cir(contours)
kernel = np.ones((5, 5), np.uint8)
- self.mask = cv2_dilate(self.mask, kernel, iterations=2)
+ self.mask = cv2.dilate(self.mask, kernel, iterations=2)
self.fill_earth()
kernel = np.ones((15, 15), np.uint8)
- self.mask = cv2_dilate(self.mask, kernel, iterations=1)
+ self.mask = cv2.dilate(self.mask, kernel, iterations=1)
- clear_earth = cv2_bitwise_and(
+ clear_earth = cv2.bitwise_and(
self.image, self.image, mask=self.mask)
- mask = cv2_bitwise_not(self.mask)
- clear_sky = cv2_bitwise_and(
+ mask = cv2.bitwise_not(self.mask)
+ clear_sky = cv2.bitwise_and(
self.image, self.image, mask=mask)
return clear_sky, clear_earth, self.mask
diff --git a/software/SAT0_OBC/SatImageTaking/star_finder.py b/software/SAT0_OBC/SatImageTaking/star_finder.py
index 8b53065..4a6f88a 100644
--- a/software/SAT0_OBC/SatImageTaking/star_finder.py
+++ b/software/SAT0_OBC/SatImageTaking/star_finder.py
@@ -1,4 +1,4 @@
-'''
+"""
@file star_finder.py
@brief A file for the finding stars function.
@@ -16,22 +16,10 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
- '''
-from cv2 import cvtColor as cv2_cvtColor
-from cv2 import morphologyEx as cv2_morphologyEx
-from cv2 import GaussianBlur as cv2_GaussianBlur
-from cv2 import threshold as cv2_threshold
-from cv2 import adaptiveThreshold as cv2_adaptiveThreshold
-from cv2 import bitwise_and as cv2_bitwise_and
-from cv2 import bitwise_not as cv2_bitwise_not
-from cv2 import Sobel as cv2_Sobel
-from cv2 import circle as cv2_circle
-from cv2 import findContours as cv2_findContours
-from cv2 import dilate as cv2_dilate
-from cv2 import minEnclosingCircle as cv2_minEnclosingCircle
-from cv2 import THRESH_TOZERO, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, MORPH_CLOSE, MORPH_OPEN, RETR_EXTERNAL,\
- CHAIN_APPROX_SIMPLE, COLOR_BGR2GRAY, THRESH_BINARY
+"""
+# 17.1.2024 asaf h: changed cv2 import cv2_ >> cv2.
+import cv2
from copy import deepcopy
# import matplotlib.pyplot as plt
import numpy as np
@@ -55,18 +43,18 @@ class star_finder:
gray_image (np.ndarray): The grayscale version of the original image.
sensitivity (int): Sensitivity of the threshold used when finding stars.
mask (np.ndarray): The mask used to find stars.
- stars (list): A list of detected stars, including center, radius, and brightness.
+ stars (list): A list of detected stars, including thier image, center(x,y), radius, and brightness.
N_stars (int): The number of stars to detect.
Methods:
find_stars(): Finds stars in the image and stores them in the 'stars' attribute.
extract_star(): Extracts a single star from the image.
get_threshold(): Returns the threshold used to find stars.
- get_brightness(): Returns the brightness of a star.
draw (): draw the stars on the image.
"""
- def __init__(self, path_or_image: str or list, gray_image=0, sensitivity=100, N_stars=None, dim=None, draw=False,) -> None:
+ # 19.9.2023 asaf h: lowered the default sensitivity for better result
+ def __init__(self, path_or_image: str or list, gray_image=0, sensitivity=50, N_stars=None, dim=None, draw=False,) -> None:
"""
Initializes the star_finder object.
"""
@@ -75,7 +63,7 @@ def __init__(self, path_or_image: str or list, gray_image=0, sensitivity=100, N_
if isinstance(gray_image, np.ndarray):
self.gray_image = gray_image
else:
- self.gray_image = cv2_cvtColor(self.image, COLOR_BGR2GRAY)
+ self.gray_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
self.sensitivity = sensitivity
self.mask = self.get_threshold()
@@ -99,22 +87,29 @@ def find_stars(self):
r - the radius of the star.
brightness- the brightness of the star.
"""
- contours, _ = cv2_findContours(
- self.mask, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE)[-2:]
+ contours, _ = cv2.findContours(
+ self.mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
stars_data = []
for cnt in contours:
- (x, y), r = cv2_minEnclosingCircle(cnt)
+ (x, y), r = cv2.minEnclosingCircle(cnt)
if r > 10:
continue
x, y, r = int(x), int(y), int(r)
center = x, y
if r == 0:
r = 1
+ r += 1
star = self.extract_star(y, x, r)
- stars_data.append(
- (star, center, r, star_finder.get_brightness(star)))
+ # 19.9.2023 asaf h: removed my get_brightness function for: brightest_pixal = np.amax(star)
+ brightest_pixal = np.amax(star)
+ # 19.9.2023 asaf h: filter out all the stars that dont not meet the minimum thresholdׄ
+ if brightest_pixal < self.sensitivity:
+ continue
- stars_data.sort(key=lambda cnt: cnt[2], reverse=True)
+ stars_data.append(
+ (star, center, r, brightest_pixal))
+ # 19.9.2023 asaf h: sort by brightest_pixal
+ stars_data.sort(key=lambda cnt: cnt[3], reverse=True)
return stars_data
def extract_star(self, y, x, r):
@@ -131,9 +126,9 @@ def extract_star(self, y, x, r):
"""
star = self.gray_image[max(y - r, 0): y + r, max(x - r, 0): x + r]
mask = np.zeros_like(self.gray_image)
- mask = cv2_circle(mask, (x, y), r, (255, 255, 255), -1)
+ mask = cv2.circle(mask, (x, y), r, (255, 255, 255), -1)
mask = mask[max(y - r, 0): y + r, max(x - r, 0): x + r]
- cropped_star = cv2_bitwise_and(star, star, mask=mask)
+ cropped_star = cv2.bitwise_and(star, star, mask=mask)
return cropped_star
def get_threshold(self):
@@ -143,37 +138,21 @@ def get_threshold(self):
Returns:
np.ndarray: Thresholded image.
"""
- gray_image = cv2_GaussianBlur(
+ gray_image = cv2.GaussianBlur(
self.gray_image, (5, 5), 0)
- _, gray_image = cv2_threshold(
- self.gray_image, self.sensitivity, 255, THRESH_TOZERO)
- adaptive_mean = cv2_adaptiveThreshold(
- gray_image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, blockSize=5, C=1)
+ _, gray_image = cv2.threshold(
+ self.gray_image, self.sensitivity, 255, cv2.THRESH_TOZERO)
+ adaptive_mean = cv2.adaptiveThreshold(
+ gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize=5, C=1)
return adaptive_mean
- @staticmethod
- def get_brightness(star):
- """
- Calculates the brightness of a star.
-
- Args:
- star (np.ndarray): Cropped star.
-
- Returns:
- int: Brightness of the star.
- """
- brightest_pixal = np.amax(star)
- p = 0.1
- threshold_pixal = brightest_pixal - brightest_pixal * p * 3
- return np.sum(star[star > threshold_pixal])
-
def draw(self):
"""
Draws the stars on the image.
"""
self.draw_image = deepcopy(self.image)
for star, center, radius, b in self.stars[:self.N_stars]:
- cv2_circle(self.draw_image, center, radius + 4, (0, 255, 0), 2)
+ cv2.circle(self.draw_image, center, radius + 4, (0, 255, 0), 2)
def get_data(self):
"""
diff --git a/software/SAT0_OBC/SatImageTaking/start_service.py b/software/SAT0_OBC/SatImageTaking/start_service.py
index b4c9069..935abe0 100644
--- a/software/SAT0_OBC/SatImageTaking/start_service.py
+++ b/software/SAT0_OBC/SatImageTaking/start_service.py
@@ -17,13 +17,9 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
'''
-from cv2 import imwrite as cv2_imwrite
-from cv2 import imread as cv2_imread
-from cv2 import cvtColor as cv2_cvtColor
-from cv2 import COLOR_BGR2GRAY, cvtColor, IMWRITE_JPEG_QUALITY
-from cv2 import INTER_AREA as cv2_INTER_AREA
-from cv2 import getGaussianKernel as cv2_getGaussianKernel
-from cv2 import resize as cv2_resize
+
+# 17.1.2024 asaf h: changed cv2 import cv2_ >> cv2.
+import cv2
import numpy as np
import os
from SatImageTaking import earth, star_finder, utils, LIT
@@ -54,7 +50,7 @@ def main(outputFolder: str, parameters_list: list) -> None:
3: makeIcon (img_path, width, height, quality_factor, gray) will create an icon out of a given image path with
custom parameters.
- 4: StarAnalysisOnPhotosThatAlreadyBeTaken (mission_count, width, height, sensitive, n_stars, with_mask) will run star analysis
+ 4: StarAnalysis (mission_count, width, height, sensitive, n_stars, with_mask) will run star analysis
on photos that have already been taken with given a custom parameters.
5: testingOnPreSavedImages (missionID, x, y, quality_factor, gray, vga, img_n) will be able to run the above functions
@@ -149,7 +145,8 @@ def main(outputFolder: str, parameters_list: list) -> None:
img_n = parameters_list[9] if len(parameters_list) > 9 else 0
mission = mission_Table[missionType]
- mission(x, y, quality_factor, gray, vga, img_n)
+ # 19.9.2023 asaf h: missionID was missing, it is like missionType, 7 arguments are needed for testing
+ mission(missionID, x, y, quality_factor, gray, vga, img_n)
def TakePhotoStarAnalysis(quality: int, width: int, height: int, Shutter: int, ISO: int) -> None:
@@ -167,13 +164,7 @@ def TakePhotoStarAnalysis(quality: int, width: int, height: int, Shutter: int, I
None
"""
print("Started TakePhotoStarAnalysis")
- if width == 0:
- width = 640
- if height == 0:
- height = 480
- if quality == 0:
- quality = 10
-
+ # 19.9.2023 asaf h: there is no need to define the parameters, takePictureWithParameters does that.
img = takePictureWithParameters(quality, width, height, Shutter, ISO)
# define Dimensions
@@ -193,8 +184,8 @@ def TakePhotoStarAnalysis(quality: int, width: int, height: int, Shutter: int, I
print("Starting writeMetaDataStars")
writeMetaDataStars(stars_list)
-
-def StarAnalysis(mission_count: int, width=1280, height=720, sensitive=100, n_stars=30, without_earth_mask=0):
+# 19.9.2023 asaf h: the default numbers needs to be removed cuz 0 is sent not None, they will be difined later
+def StarAnalysis(mission_count: int, width: int, height: int, sensitive: int, n_stars: int, without_earth_mask=0):
"""Analyzes an image to identify stars
Args:
@@ -209,12 +200,13 @@ def StarAnalysis(mission_count: int, width=1280, height=720, sensitive=100, n_st
stars_list (list): A list of the detected stars in the image
"""
print("Started StarAnalysis")
+ # 19.9.2023 asaf h: fixed the default numbers
if width == 0:
- width = 640
+ width = 1280
if height == 0:
- height = 480
+ height = 720
if sensitive == 0:
- sensitive = 100
+ sensitive = 50
if n_stars == 0:
n_stars = 30
@@ -227,7 +219,8 @@ def StarAnalysis(mission_count: int, width=1280, height=720, sensitive=100, n_st
# star detection
detected_object = findStarsNoDarkEarth(img, img_object, sensitive, n_stars)
- detected_object.draw()
+ # 19.9.2023 asaf h: detected_object.draw() and saveFinalImg(detected_object.draw_image, "Detected")
+ # will save the image with the green circels on the stars on the pi for future analysis. its unnecessary.
# get stars list:
stars_list = get_stars(detected_object)
@@ -236,34 +229,17 @@ def StarAnalysis(mission_count: int, width=1280, height=720, sensitive=100, n_st
print("Starting writeMetaDataStars")
writeMetaDataStars(stars_list)
print("Starting saveFinalImg")
- saveFinalImg(detected_object.draw_image, "Detected")
-
-
-def takeStandardPicture() -> np.ndarray:
- """Takes a standard picture with default raspistill image capture parameters.
- The picture is taken by a cmd function
-
- Returns:
- img (np.ndarray): A numpy array containing the image
- """
-
- print("Started takeStandardPicture")
- comm = f"raspistill -o {output}/Img.jpeg"
- print(comm)
- os.system(comm)
- read = f"{output}/Img.jpeg"
- print(read)
- img = cv2_imread(read)
- return img
+# 19.9.2023 asaf h: removed takeStandardPicture function cuz there is no need to. check line 268 (else)
+# 19.9.2023 asaf h: fixed the main function takePictureWithParameters. rony please double check it again. it should be fine
def takePictureWithParameters(quality: int, width: int, height: int, Shutter: int, ISO: int) -> np.ndarray:
"""Take a picture with specified parameters
Args:
- quality (int): The quality of the image (default 10)
- width (int): The width of the image (default 640)
- height (int): The height of the image (default 480)
+ quality (int): The quality of the image (default 100)
+ width (int): The width of the image (default 1280)
+ height (int): The height of the image (default 720)
Shutter (int): The shutter speed of the camera (default 0)
ISO (int): The ISO of the camera (default 0)
@@ -273,35 +249,26 @@ def takePictureWithParameters(quality: int, width: int, height: int, Shutter: in
print("Started takePictureWithParameters")
if quality == 0:
- quality = 10
+ quality = 100
if width == 0:
- width = 640
+ width = 1280
if height == 0:
- height = 480
+ height = 720
- if (quality != 100 and width != 1280 and height != 720 and Shutter != 0 and ISO != 0):
+ if (Shutter != 0 and ISO != 0):
command_with_parameters = f"raspistill -o {output}/Img.jpeg --quality {quality} --width {width} --height {height} --shutter {Shutter} --ISO {ISO} -th none"
- os.system(command_with_parameters)
- read = f"{output}/Img.jpeg"
- img = cv2_imread(read)
- elif (quality != 100 and width != 1280 and height != 720 and Shutter != 0):
+ elif (Shutter != 0):
command_with_parameters = f"raspistill -o {output}/Img.jpeg --quality {quality} --width {width} --height {height} --shutter {Shutter} -th none"
- os.system(command_with_parameters)
- read = f"{output}/Img.jpeg"
- img = cv2_imread(read)
- elif (quality != 100 and width != 1280 and height != 720):
- command_with_parameters = f"raspistill -o {output}/Img.jpeg --quality {quality} --width {width} --height {height} -th none"
- os.system(command_with_parameters)
- read = f"{output}/Img.jpeg"
- img = cv2_imread(read)
- elif (quality != 100):
- command_with_parameters = f"raspistill -o {output}/Img.jpeg --quality {quality} -th none"
- os.system(command_with_parameters)
- read = f"{output}/Img.jpeg"
- img = cv2_imread(read)
+ elif (ISO != 0):
+ command_with_parameters = f"raspistill -o {output}/Img.jpeg --quality {quality} --width {width} --height {height} --ISO {ISO} -th none"
else:
- img = takeStandardPicture()
- read = f"{output}/Img.jpeg"
+ command_with_parameters = f"raspistill -o {output}/Img.jpeg --quality {quality} --width {width} --height {height} -th none"
+
+ # 19.9.2023 asaf h: removed the take standard picture. unnecessary function
+
+ os.system(command_with_parameters)
+ read = f"{output}/Img.jpeg"
+ img = cv2.imread(read)
print("Compressing")
CompressImage(img, output, save_full=True)
@@ -313,8 +280,8 @@ def takePictureWithParameters(quality: int, width: int, height: int, Shutter: in
writeMetaDataSmallImg(read, isGoodImage)
return img
-
-def findStarsNoDarkEarth(img: np.ndarray, img_object: np.ndarray, sensitive=100, n_stars=30) -> np.ndarray:
+# 19.9.2023 asaf h: lower the default sensitive for better result
+def findStarsNoDarkEarth(img: np.ndarray, img_object: np.ndarray, sensitive=50, n_stars=30) -> np.ndarray:
"""Finds stars in an image while the Earth is lit and not dark
Args:
@@ -326,7 +293,7 @@ def findStarsNoDarkEarth(img: np.ndarray, img_object: np.ndarray, sensitive=100,
Returns:
detected_object (np.ndarray): An array containing the detected objects
"""
- gray_image = cvtColor(img_object.clear_sky, COLOR_BGR2GRAY)
+ gray_image = cv2.cvtColor(img_object.clear_sky, cv2.COLOR_BGR2GRAY)
star_detection = star_finder.star_finder(
img, gray_image, sensitivity=sensitive, N_stars=n_stars)
return star_detection
@@ -431,10 +398,10 @@ def crop_and_compress(mission_count: int, x: int, y: int, quality_factor=95, gra
img = utils.get_image(mission_count)
crop_img = utils.crop(img, x, y, qvga)
if(gray):
- crop_img = cv2_cvtColor(crop_img, COLOR_BGR2GRAY)
+ crop_img = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)
saveFinalImg(crop_img, 'Img', quality_factor)
read = f"{output}/Img.jpeg"
- cropped_img = cv2_imread(read)
+ cropped_img = cv2.imread(read)
CompressImage(cropped_img, output, save_full=True)
makeIcon(crop_img)
@@ -449,7 +416,7 @@ def decideIfGoodImage(img: np.ndarray) -> bool:
int: 1 if the image is good, 0 otherwise.
"""
img = utils.get_image(img)
- img = cv2_cvtColor(img, COLOR_BGR2GRAY)
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
w, h = img.shape
black_percent = np.sum(img < 15)*100/(w*h)
return 1 if black_percent > 95 else 0
@@ -478,9 +445,9 @@ def makeIcon(img_path: str, width=80, height=80, quality_factor=21, gray=0) -> N
dim = (width, height)
img = utils.get_image(img_path)
- resized_image = cv2_resize(img, dim, interpolation=cv2_INTER_AREA)
+ resized_image = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
if gray:
- resized_image = cvtColor(resized_image, COLOR_BGR2GRAY)
+ resized_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY)
saveFinalImg(resized_image, 'icon', quality_factor)
@@ -496,8 +463,8 @@ def saveFinalImg(star_detection: np.ndarray, name: str, compress_factor=95) -> N
None.
"""
FINAL_PATH = f"{output}/{name}.jpeg"
- compress = [IMWRITE_JPEG_QUALITY, compress_factor]
- cv2_imwrite(FINAL_PATH, star_detection, compress)
+ compress = [cv2.IMWRITE_JPEG_QUALITY, compress_factor]
+ cv2.imwrite(FINAL_PATH, star_detection, compress)
def testing(missionType: int, x: int, y: int, quality_factor: int, gray: bool, qvga: bool, img_n=0) -> int:
@@ -517,7 +484,16 @@ def testing(missionType: int, x: int, y: int, quality_factor: int, gray: bool, q
"""
img_path = f"SatImageTaking/photos{img_n}.jpeg"
mission = mission_Table[missionType]
- mission(img_path, x, y, quality_factor, gray, qvga)
+ # 19.9.2023 asaf h: each function has its own order
+ if mission == makeIcon: #
+ mission(img_path, x, y, quality_factor, gray)
+ elif mission == crop_and_compress:
+ mission(img_path, x, y, quality_factor, gray, qvga)
+ else: #StarAnalysis
+ sensitive = quality_factor
+ n_stars = gray
+ without_earth_mask = qvga
+ mission(img_path, x, y, sensitive, n_stars, without_earth_mask)
def CompressImage(in_img: np.ndarray, path: str, max_size: int = 16 * LIT.KBYTE, comp_gray=True, save_full=False) -> str and np.ndarray:
@@ -535,9 +511,9 @@ def CompressImage(in_img: np.ndarray, path: str, max_size: int = 16 * LIT.KBYTE,
"""
img = in_img
if len(in_img.shape) > 2 and comp_gray:
- img = cv2_cvtColor(img, COLOR_BGR2GRAY)
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = img / 255
- g_ker = cv2_getGaussianKernel(5, -1)
+ g_ker = cv2.getGaussianKernel(5, -1)
g_ker = g_ker @ g_ker.T
lap_pyr = LIT.pyrLap(img, 7, g_ker)
jp2_img = img[:, :, [2, 1, 0]] if len(img.shape) > 2 else img
@@ -556,3 +532,4 @@ def CompressImage(in_img: np.ndarray, path: str, max_size: int = 16 * LIT.KBYTE,
mission_Table = {0: TakePhotoStarAnalysis, 1: takePictureWithParameters,
2: crop_and_compress, 3: makeIcon, 4: StarAnalysis, 5: testing}
+
diff --git a/software/SAT0_OBC/SatImageTaking/utils.py b/software/SAT0_OBC/SatImageTaking/utils.py
index c9fbf7f..cec8a03 100644
--- a/software/SAT0_OBC/SatImageTaking/utils.py
+++ b/software/SAT0_OBC/SatImageTaking/utils.py
@@ -17,11 +17,10 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
'''
-from cv2 import imwrite as cv2_imwrite
-from cv2 import imread as cv2_imread
-from cv2 import resize as cv2_resize
-from cv2 import INTER_AREA as cv2_INTER_AREA
-from cv2 import IMWRITE_JPEG_QUALITY
+
+# 17.1.2024 asaf h: changed cv2 import cv2_ >> cv2.
+import cv2
+
from datetime import datetime
import os
import numpy as np
@@ -45,7 +44,7 @@ def get_image(path_or_image: str or np.ndarray, x=-1, dim=None) -> np.ndarray:
image = path_or_image
elif isinstance(path_or_image, int):
path = f"./sent/{path_or_image}/Img.jpeg"
- image = cv2_imread(path, -1)
+ image = cv2.imread(path, -1)
else:
raise TypeError("pass path or image")
return image
@@ -62,9 +61,9 @@ def _read_image(path: str, x=-1, dim=None) -> np.ndarray:
Returns:
np.ndarray: Image.
"""
- image = cv2_imread(path, x)
+ image = cv2.imread(path, x)
if dim and len(dim):
- image = cv2_resize(image, dim)
+ image = cv2.resize(image, dim)
return image
@@ -78,7 +77,8 @@ def get_pic_path_list(path: str) -> list:
list: List of path of images in the directory.
"""
file_list = os.listdir(path)
- pic_path_list = [path + i for i in file_list if i.endswith(('.png', '.jpg', '.jpeg', '.jfif')) and
+ # 19.9.2023 asaf h: fix bug
+ pic_path_list = [path + '/' + i for i in file_list if i.endswith(('.png', '.jpg', '.jpeg', '.jfif')) and
not i.startswith('.')]
return pic_path_list
@@ -172,11 +172,11 @@ def save_pic(pic_path: str, image: np.ndarray, compress_factor=95, dim=None) ->
None
"""
if dim and len(dim) == 2:
- image = cv2_resize(image, dim)
+ image = cv2.resize(image, dim)
image_name = datetime.now().strftime("%Y-%m-%d %H-%M-%S-%f") + '.jpeg'
image_path = os.path.join(pic_path, image_name)
- compress = [IMWRITE_JPEG_QUALITY, compress_factor]
- cv2_imwrite(image_path, image, compress)
+ compress = [cv2.IMWRITE_JPEG_QUALITY, compress_factor]
+ cv2.imwrite(image_path, image, compress)
def resize(img: np.ndarray, dim=(60, 60)) -> np.ndarray:
@@ -189,5 +189,5 @@ def resize(img: np.ndarray, dim=(60, 60)) -> np.ndarray:
Returns:
np.ndarray: The resized image.
"""
- new_img = cv2_resize(img, dim, Interpolation=cv2_INTER_AREA)
+ new_img = cv2.resize(img, dim, Interpolation=cv2.INTER_AREA)
return new_img
diff --git a/software/SAT0_OBC/controller.py b/software/SAT0_OBC/controller.py
index c031c42..88841d3 100644
--- a/software/SAT0_OBC/controller.py
+++ b/software/SAT0_OBC/controller.py
@@ -254,7 +254,7 @@ def msgArrived(self, msgByte):
elif command == CmdTypes.CMD_UPLOAD_FILE.value: # 16
print("*** CmdTypes.CMD_UPLOAD_FILE ***")
-
+
# set state to in mission and sendmsg
self.state = StateTypes.STATE_BUSY.value
self.serial.sendMsg(bytearray([ApiTypes.API_ACK.value]))
@@ -273,18 +273,18 @@ def msgArrived(self, msgByte):
scriptNum = paramsList[1]
line_num = paramsList[2]
num_chars = paramsList[3]
-
+
add = lambda i: chr(int(hex(i), 16))
txt = ''.join([add(i) for i in paramsList[4: 4 + num_chars]])
-
- reset = 1 if len(paramsList[: 4 + num_chars]) < len(paramsList) and paramsList[-1] != 0 else 0 #TODO how to reset
+ # 19.9.2023 asaf h: To reset the file it is better to send 1 instead of not 0.
+ reset = 1 if len(paramsList[: 4 + num_chars]) < len(paramsList) and paramsList[-1] == 1 else 0
# execute mission with parameters:
- print('parms: * > * > ' , f'missionCount: {missionCount}, scriptNum: {scriptNum}, ', end='')
+ print('parms: * > * > ' , f'missionCount: {missionCount}, scriptNum: {scriptNum}, ', end='')
print(f'line_num: {line_num}, num_chars: {num_chars}, txt: {repr(txt)}, reset: {reset}')
-
+
import uploading
uploading.main(missionCount, scriptNum, line_num, txt, reset)
-
+
# finished executing mission:
self.state = StateTypes.STATE_READY.value
print("*** CmdTypes.CMD_UPLOAD_FILE Done ***")
diff --git a/software/SAT0_OBC/uploading.py b/software/SAT0_OBC/uploading.py
index 4a4a576..71e67e1 100644
--- a/software/SAT0_OBC/uploading.py
+++ b/software/SAT0_OBC/uploading.py
@@ -1,6 +1,7 @@
import numpy as np
import os
+
def insert_line(script: list, line_num: int, line: int) -> None:
x = -1 if script[-1] == '#Execute script' else 0
line_num -= 1 # cuz main():
@@ -15,8 +16,8 @@ def insert_line(script: list, line_num: int, line: int) -> None:
for i in range(len(script) + x, line_num + 2)]
script.insert(line_num, line)
-
-def writing_file(file_num: int, num_line: int, script_txt: str, file_path) -> None:
+ # 19.9.2023 asaf h: file_num not in use, it is on file_path, changed also line 148.
+def writing_file(num_line: int, script_txt: str, file_path) -> None:
# defultive script
"""
def main():
@@ -24,7 +25,9 @@ def main():
if __name__ == "__main__"
main()
"""
- Tab = ' '*4
+ # 19.9.2023 asaf h: enable to insert multiple lines at once.
+ script_txt = script_txt.replace('\n', '\n\t').strip('\t')
+ Tab = '\t'
line = Tab + script_txt
num_line += 1 # cuz main():
@@ -56,7 +59,7 @@ def reset_file(script_path: str) -> None:
f.writelines(file)
-def execute_file(file_name: str, script_path:str) -> list:
+def execute_file(file_name: str, script_path: str) -> list:
def module_from_file(module_name, file_path):
import importlib.util
@@ -77,20 +80,22 @@ def module_from_file(module_name, file_path):
eror = format_tb(exception_traceback)[-1]
print(eror)
line_num = int(eror[eror.find(',') + 1: eror.rfind(',')
- ].replace('line', '').strip())
+ ].replace('line', '').strip())
if isinstance(exception_object, SyntaxError): # bypass problem in that eror
line_num = exception_object.lineno
run_success = False
- line_num -= 1 # cuz main()
+ line_num -= 1 # cuz main()
info = [run_success, file_name, line_num]
print(info)
return info
-def check_execute(file_name, script_line, script_path):
- if script_line.find('\n') == -1:
+# 19.9.2023 asaf h: file_num not in use, it is on file_path, changed also line 151.
+def check_execute(script_line, script_path):
+ # 19.9.2023 asaf h: enable to insert multiple lines at once.
+ if not script_line.endswith("\n"):
return True
with open(script_path, 'r') as f:
last_line = f.readlines()[-1]
@@ -100,7 +105,7 @@ def check_execute(file_name, script_line, script_path):
def writeMetaFile(mission_count: int, data: list) -> list:
run_success, file_name = data[:2]
if run_success:
- chars_length, result = data[2:]
+ chars_length, result = data[2:]
else:
eror_line_num = data[2:]
@@ -109,7 +114,7 @@ def writeMetaFile(mission_count: int, data: list) -> list:
file_num = int(''.join(i for i in file_name if i.isdigit()))
with open(FINAL_PATH, 'wb+') as f:
- hex_byte_trans = lambda x: np.array(x).astype(np.uint8).tobytes()
+ def hex_byte_trans(x): return np.array(x).astype(np.uint8).tobytes()
b_run_success = hex_byte_trans(run_success)
b_file_num = hex_byte_trans(file_num)
@@ -122,30 +127,29 @@ def writeMetaFile(mission_count: int, data: list) -> list:
f.write(b_chars_length)
f.write(bytes(result, 'utf-8'))
- print(b_run_success + b_file_num + b_chars_length + bytes(result, 'utf-8'))
+ print(b_run_success + b_file_num +
+ b_chars_length + bytes(result, 'utf-8'))
else:
b_eror_line_num = hex_byte_trans(eror_line_num)
f.write(b_eror_line_num)
print(b_run_success + b_file_num + b_eror_line_num)
-
-
def main(mission_count: int, script_num: int, line_num: int, txt: str, reset):
path = "/home/pi/scripts_folder/"
if isinstance(path, str) and not os.path.exists(path):
- os.makedirs(path)
-
+ os.makedirs(path)
+
file_name = 'script' + str(script_num) + '.py'
script_path = path + file_name
if reset or not os.path.exists(script_path):
reset_file(script_path)
-
- writing_file(script_num, line_num, txt, script_path)
-
- if check_execute(file_name, txt, script_path):
+ # 19.9.2023 asaf h: file_num not in use, it is on file_path, changed also line 20.
+ writing_file(line_num, txt, script_path)
+ # 19.9.2023 asaf h: file_num not in use, it is on file_path, changed also line 95.
+ if check_execute(txt, script_path):
import time
time.sleep(0.5)
info = execute_file(file_name, script_path)
@@ -153,10 +157,8 @@ def main(mission_count: int, script_num: int, line_num: int, txt: str, reset):
else:
FINAL_PATH = f"./outbox/{mission_count}/_metaUploadingFile.bin"
with open(FINAL_PATH, 'wb+') as f:
- f.write(np.array(line_num).astype(np.uint8).tobytes())
- print(f'changed line: {line_num}, {np.array(line_num).astype(np.uint8).tobytes()}')
-
-
-
-if __name__ == "__main__":
- main()
+ f.write(np.array(script_num).astype(np.uint8).tobytes())
+ f.write(np.array(line_num).astype(np.uint8).tobytes())
+ print(
+ f'changed line: {line_num}, {np.array(line_num).astype(np.uint8).tobytes()}')
+# 19.9.2023 asaf h: no need of if __name__ == "__main__":.