Module AmpliVision.src.objs.test_analyzer.strip_section
Classes
class StripSection (test_square_img: numpy.ndarray, strip_type: str, rotation: int)
-
This class is responsible for holding data and processes regarding sections of test inner square (bkg, test, or control)
Expand source code
class StripSection: "This class is responsible for holding data and processes regarding sections of test inner square (bkg, test, or control)" def __init__(self, test_square_img: np.ndarray, strip_type: str, rotation: int): self.strip_type = strip_type self.bounds = self.set_bounds(test_square_img, rotation) # each spot is hashmap {"contour": np.ndarray, "avg_rgb": int, "positive": bool} self.spots = [] self.total_avg_rgb = None def __str__(self): return f"StripSection of type {self.strip_type} with bounds {self.bounds} and {len(self.spots)} spots." def print_spots(self): "prints the spots in the section" for spot in self.spots: print(f"{self.strip_type} spot: ", spot["avg_rgb"], " positive: ", spot["positive"]) def add_spot(self, block, contour: np.ndarray, result: bool, debug: bool = False) -> None: " adds spot to section as a hashmap with \"color\" and \"avg_rgb\" " avg_rgb = get_rgb_avg_of_contour(block, contour) print(f"spot: {avg_rgb} positive: {result}") if debug else None if result == False: avg_rgb = (0,0,0) self.spots.append({ "contour": contour, "avg_rgb": list(avg_rgb), "positive": result }) if debug: copy = block.get_test_area_img().copy() val = self.bounds cv.rectangle(copy, (val[0], val[1]), (val[2], val[3]), (0, 255, 0), 1) cv.drawContours(copy, [contour], -1, (0, 0, 255), 1) copy = cv.resize(copy, (200, 200)) """ cv.imshow('stripSection/add_spot()', copy) cv.waitKey(0)#""" cv.destroyAllWindows()#""" self.set_total_avg_rgb() def set_spots_manually(self, block, debug: bool = False) -> None: "mostly used to find negative result spots using ratios" copy = block.get_test_area_img().copy() val = self.bounds spot_center = ( int((val[0] + val[2])/2), int((val[1] + val[3])/2) ) spot = self.identify_spot_manually( copy, spot_center, debug=debug ) # result should be set to True on real cases where spot is hard to find with hsv # otherwise, set to False self.add_spot(block, spot, True, debug=debug) def identify_spot_manually(self, test_area_img, circ_center, debug: bool) -> np.ndarray: "used to identify a spot manually" # get the contour of circle spott copy = test_area_img.copy() cv.circle(copy, (circ_center[0], circ_center[1]), 5, (0, 0, 255), 1) # isolate the red circle color hsv = cv.cvtColor(copy, cv.COLOR_BGR2HSV) lower_red = np.array([0, 250, 250]) upper_red = np.array([0, 255, 255]) mask = cv.inRange(hsv, lower_red, upper_red) contours, _ = cv.findContours( mask, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) if debug: copy = cv.drawContours(copy, contours, -1, (255, 0, 0), 1) copy = cv.resize(copy, (200, 200)) plt.imshow(copy) plt.show() return contours[0] def set_total_avg_rgb(self, bkg=[0, 0, 0]) -> list[int]: "sets the total avg rgb by adding the spot rgb avgs together" #assert len(self.spots) != 0, """ #please add spots to section before calling set_total_avg_rgb()""" if len(self.spots) == 0: self.total_avg_rgb = 0 return i = 0 total_avg = [0, 0, 0] # adding the total avg with each spot avg for spot in self.spots: total_avg = list( map( lambda total, spot_avg: total + spot_avg ,total_avg, spot["avg_rgb"] ) ) i += 1 # dividing by the number of spots total_avg = list( map( lambda total: total/i , total_avg ) ) self.total_avg_rgb = total_avg def subtract_bkg(self, bkg_rgb_avg: list[int]) -> list[int]: "subtracts the bkg rgb from the total avg rgb" if self.total_avg_rgb == None: print("please set the total avg rgb before calling subtract_bkg()") return None return list( map( lambda total, bkg: bkg - total , self.total_avg_rgb, bkg_rgb_avg ) ) # geometry def set_bounds(self, test_square_img: np.ndarray, rotation: int) -> list[int]: # test strip component bounds x, y, = 0, 0 # Shape returns: (height, width, channels) h, w = test_square_img.shape[:2] bounds = None # divide the square into 3 sections along the middle strip (bkg, test, control) # ASSUMPTION: this order ASSUMES the strip is vertical with bkg on bottom if rotation == 0: if self.strip_type == "spot2": # [top left x, top left y, width, height] bounds = [x+int(w/3), y, x+int(2/3*w), y+int(h/4)] elif self.strip_type == "spot1": bounds = [x+int(w/3), y+int(h/3), x+int(2/3*w), y+int(2/3*h)] if self.strip_type == "bkg": bounds = [x+int(w/3), y+int(3/4*h), x+int(2/3*w), y+h] elif rotation == 90: if self.strip_type == "bkg": bounds = [x, y+int(h/3), x+int(w*1/4), y+int(2/3*h)] elif self.strip_type == "spot1": bounds = [x+int(w/3), y+int(h/3), x+int(2/3*w), y+int(2/3*h)] elif self.strip_type == "spot2": bounds = [x+int(w*3/4), y+int(h/3), x+w, y+int(h*2/3)] elif rotation == 180: if self.strip_type == "bkg": # [top left x, top left y, width, height] bounds = [x+int(w/3), y, x+int(2/3*w), y+int(h/4)] elif self.strip_type == "spot1": bounds = [x+int(w/3), y+int(h/3), x+int(2/3*w), y+int(2/3*h)] if self.strip_type == "spot2": bounds = [x+int(w/3), y+int(3/4*h), x+int(2/3*w), y+h] elif rotation == 270: if self.strip_type == "spot2": bounds = [x, y+int(h/3), x+int(w*1/4), y+int(2/3*h)] elif self.strip_type == "spot1": bounds = [x+int(w/3), y+int(h/3), x+int(2/3*w), y+int(2/3*h)] elif self.strip_type == "bkg": bounds = [x+int(w*3/4), y+int(h/3), x+w, y+int(h*2/3)] return bounds def bounds_contour(self, contour) -> bool: "checks if contour is within section bounds" x, y, w, h = cv.boundingRect(contour) center_point = (x+w/2, y+h/2) if center_point[0] >= self.bounds[0] and center_point[0] <= self.bounds[2] and center_point[1] >= self.bounds[1] and center_point[1] <= self.bounds[3]: return True return False def paint_spot(self, block_img, rgb, display=False): "paints the spot on the block image" if len(self.spots) > 0: block_img = cv.drawContours(block_img, [self.spots[-1]["contour"]], -1, rgb, -1) if display: cv.imshow('paint_spot()', block_img) cv.waitKey(0) cv.destroyAllWindows() return block_img
Methods
def add_spot(self, block, contour: numpy.ndarray, result: bool, debug: bool = False) ‑> None
-
adds spot to section as a hashmap with "color" and "avg_rgb"
def bounds_contour(self, contour) ‑> bool
-
checks if contour is within section bounds
def identify_spot_manually(self, test_area_img, circ_center, debug: bool) ‑> numpy.ndarray
-
used to identify a spot manually
def paint_spot(self, block_img, rgb, display=False)
-
paints the spot on the block image
def print_spots(self)
-
prints the spots in the section
def set_bounds(self, test_square_img: numpy.ndarray, rotation: int) ‑> list[int]
def set_spots_manually(self, block, debug: bool = False) ‑> None
-
mostly used to find negative result spots using ratios
def set_total_avg_rgb(self, bkg=[0, 0, 0]) ‑> list[int]
-
sets the total avg rgb by adding the spot rgb avgs together
def subtract_bkg(self, bkg_rgb_avg: list[int]) ‑> list[int]
-
subtracts the bkg rgb from the total avg rgb