From 54b87784a41b718e41911b71174c65a19ad3fe61 Mon Sep 17 00:00:00 2001 From: gattlin1 Date: Wed, 16 Oct 2019 21:35:32 -0500 Subject: [PATCH 1/4] Adding mbv2 to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 91d74cc..96e6e67 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ Server/resources/uploads/* test/resources/sample*/*Copy* uploads/ .vscode -venv/ \ No newline at end of file +venv/ +mbv2/ \ No newline at end of file From 04228091d9bc65c4b32fab8434fed1614b853384 Mon Sep 17 00:00:00 2001 From: gattlin1 Date: Thu, 17 Oct 2019 17:29:49 -0500 Subject: [PATCH 2/4] Fixing typo that wasn't allowing the radius option for color detection to work. --- .gitignore | 3 ++- Server/templates/index.html | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e238f67..51362d3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ test/resources/sample*/*Copy* uploads/ .vscode venv/ -*.pyc \ No newline at end of file +*.pyc +mbv2/ \ No newline at end of file diff --git a/Server/templates/index.html b/Server/templates/index.html index 50fd048..4906a0f 100644 --- a/Server/templates/index.html +++ b/Server/templates/index.html @@ -109,8 +109,8 @@

M.O.S.A.I.C

Color Detection Algorithm From 61fd004f18ad841b252eb121f9d86d29de86b8c3 Mon Sep 17 00:00:00 2001 From: gattlin1 Date: Sat, 19 Oct 2019 16:37:02 -0500 Subject: [PATCH 3/4] Improved on the crushed bead processing. Changed the naming convention of color labeler to camel case. --- lib/{color_labeler.py => colorLabeler.py} | 2 +- lib/counting.py | 85 +++++++++++++++++------ 2 files changed, 66 insertions(+), 21 deletions(-) rename lib/{color_labeler.py => colorLabeler.py} (90%) diff --git a/lib/color_labeler.py b/lib/colorLabeler.py similarity index 90% rename from lib/color_labeler.py rename to lib/colorLabeler.py index 15d0329..952c5d1 100644 --- a/lib/color_labeler.py +++ b/lib/colorLabeler.py @@ -5,7 +5,7 @@ class ColorLabeler: def __init__(self): - self.colorsToIgnore = ['darkgray', 'darkblue', 'black'] + self.colorsToIgnore = ['darkgray', 'darkblue', 'black', 'white'] colors = OrderedDict({ "red": (255, 0, 0), diff --git a/lib/counting.py b/lib/counting.py index e8d33c5..a2ee472 100644 --- a/lib/counting.py +++ b/lib/counting.py @@ -36,7 +36,7 @@ from enum import Enum from os import listdir, path from . import util -from . import color_labeler +from . import colorLabeler """ Description: an enum class to handle the HoughCircle configuration values that are used in cv2.HoughCircles(). @@ -58,6 +58,7 @@ def __init__(self, imagePath): self.imagePath = imagePath self.grayScaleMap = cv2.imread(imagePath,0) # create grayscale cv2 img self.colorMap = cv2.imread(imagePath) # create color cv2 img + self.labMap = cv2.cvtColor(self.colorMap, cv2.COLOR_BGR2Lab) self.colorBeads = [] self.waterBeads = [] self.crushedBeads = [] @@ -103,7 +104,7 @@ def getColorBeads(self, houghConfig, detectionParams): self.waterBeads.append(color) if detectionParams.wantsCrushedBeads: # if the user wants to detect crushed beads. - self.getCrushedBeads(cimg, circles) + self.getCrushedBeads(cimg) imagePath = '/'.join(self.imagePath.split('/')[:-2]) + '/results/' imagePath += 'result_image.jpg'#+ str(fileNum) +'.jpg' @@ -132,39 +133,83 @@ def isWater(self, RGB): isWater = True return isWater - def getCrushedBeads(self, image, circles): - temp_img = self.grayScaleMap.copy() + """ + Description: does preprocessing on the image map to find the crushed beads. + @param image - image that will have the final results of the counting + """ + def getCrushedBeads(self, image): + mask = np.ones(image.shape[:2], dtype="uint8") + knownObjects = self.colorBeads + self.waterBeads - for i in circles[0,:]: + # takes the known objects (beads and water beads) and colors them black + # so they can be ignored when detecting the crushed beads + for bead in knownObjects: # fills in the circle - cv2.circle(temp_img, (i[0],i[1]) ,i[2], (255,255,255), -1) + cv2.circle(mask, (bead[2][0],bead[2][1]), bead[2][2], (0,0,0), -1) #fills the outer edges of the circle - cv2.circle(temp_img,(i[0], i[1]), i[2], (255,255,255), 17) + cv2.circle(mask, (bead[2][0],bead[2][1]), bead[2][2], (0,0,0), 17) + color = cv2.bitwise_and(self.colorMap, self.colorMap, mask=mask) - blur = cv2.GaussianBlur(temp_img, (19, 19), 0) - lab = cv2.cvtColor(self.colorMap, cv2.COLOR_BGR2LAB) - thresh = cv2.threshold(blur, 225, 255, cv2.THRESH_BINARY_INV)[1] - img_output, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + # gathers the locations for the white background and + # colors it white so it won't affect the contour detection + minBg = (235, 235, 235) + maxBg = (255, 255, 255) + self.removeImgAspect(color, minBg, maxBg) - cl = color_labeler.ColorLabeler() + # gathers the locations of the black areas from stitching and + # colors it white so it won't affect the contour detection + minBlack = (0, 0, 0) + maxBlack = (10, 10, 10) + self.removeImgAspect(color, minBlack, maxBlack) - for c in contours: - color = cl.label(lab, c) + lab = cv2.cvtColor(color, cv2.COLOR_BGR2LAB) + + # gathers the locations of the black borders around the beads and + # colors it white so it won't affect the contour detection + minBorder = (0, 0, 0) + maxBorder = (180, 190, 130) + self.removeImgAspect(lab, minBorder, maxBorder, drawing=color) - if color not in cl.colorsToIgnore: - cv2.drawContours(image, [c], -1, (0, 255, 0), 2) + gray = cv2.cvtColor(color, cv2.COLOR_BGR2GRAY) + blur = cv2.GaussianBlur(gray, (31, 31), 0) + thresh = cv2.threshold(blur, 225, 255, cv2.THRESH_BINARY_INV)[1] + imgOutput, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + cl = colorLabeler.ColorLabeler() + + for c in contours: + color_label = cl.label(self.labMap, c) + if color_label not in cl.colorsToIgnore: + cv2.drawContours(image, [c], -1, (255, 0, 0), 4) - # compute the center of the contour M = cv2.moments(c) if M['m00'] > 0: cX = int((M["m10"] / M["m00"])) cY = int((M["m01"] / M["m00"])) self.crushedBeads.append([[0, 0, 0], 'crushedBead', [cX, cY, 35]]) else: - cX = 0 - cY = 0 - cv2.circle(image, (cX, cY), 2, (0, 255, 0), 3) + cX = cY = 0 + cv2.circle(image, (cX, cY), 2, (255, 0, 0), 3) + + """ + Description: Gets the locations of pixels within a given bound and colors + them white so they will not be picked up during image detection + @param img - the image used to find the pixels withing a given range + @param minBound - the lower bound of a pixel's color intensity + @param maxBound - the upper bound of a pixel's color intensity + @param drawing - an optional parameter in case the image the results need to be drawn on + is different than the image the range detection was performed on. + """ + def removeImgAspect(self, img, minBound, maxBound, drawing=[]): + # if no drawing image is given then it becomes the original img + if len(drawing) == 0: + drawing = img + + aspect = cv2.inRange(img, minBound, maxBound) + imgOutput, contours, hierarchy = cv2.findContours(aspect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + for c in contours: + cv2.drawContours(drawing, [c], -1, (255, 255, 255), -1) """ Description: a function that takes an array representing a circle's[x-coord of center, y-coord of center, radius] From 8c0a4d1301885d526d7d4ec42461e2e6e0a3ca2f Mon Sep 17 00:00:00 2001 From: gattlin1 Date: Sun, 20 Oct 2019 14:45:12 -0500 Subject: [PATCH 4/4] Adding logic to delete the results banner if the user is not hovering over it. --- Server/resources/js/mapInspector.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Server/resources/js/mapInspector.js b/Server/resources/js/mapInspector.js index deeff76..5178376 100644 --- a/Server/resources/js/mapInspector.js +++ b/Server/resources/js/mapInspector.js @@ -133,6 +133,9 @@ var imageObj = undefined; //the stitched map image // fill in the object information (rgb, location, radius) into the textbox ctx.fillText(information, rectX + 10, rectY + (rectHeight / 1.5), rectX + rectWidth); } + else { + redraw(ctx); + } }; /*