def repaintArea(self): self._overlay_stack.append(self.mask_pixmap.copy()) if self.direct_mask_paint: self._offscreen_mask_stack.append(self._offscreen_mask.copy()) orig_mask = self.mask_pixmap.toImage().convertToFormat( QImage.Format_ARGB32) msk = alpha_view(orig_mask).copy() msk[np.where((msk > 0))] = 255 msk = 255 - msk msk1 = 255 - np.copy(msk) the_mask = cv2.copyMakeBorder(np.zeros(msk1.shape[:2], np.uint8), 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0) seed_point = (int(self.lastCursorLocation.x()), int(self.lastCursorLocation.y())) cv2.floodFill(msk1, the_mask, seed_point, 0, 0, 1) paintin = np.bitwise_xor(msk, msk1) new_img = np.dstack((rgb_view(orig_mask), alpha_view(orig_mask))) new_img[np.where( (paintin == 0))] = list(self.brush_fill_color.getRgb()) new_qimg = array2qimage(new_img) if self.direct_mask_paint: omask = byte_view(self._offscreen_mask).copy() omask = omask.reshape(omask.shape[:-1]) tc = self.d_rgb2gray[self.brush_fill_color.name()] omask[np.where((paintin == 0))] = tc self._offscreen_mask = QImage(omask.data, omask.shape[1], omask.shape[0], omask.strides[0], QImage.Format_Grayscale8) self.mask_pixmap = QPixmap.fromImage(new_qimg) self._overlayHandle.setPixmap(self.mask_pixmap)
def test_alpha_view(): qimg = QtGui.QImage(320, 240, QtGui.QImage.Format_ARGB32) qimg.fill(23) v = qimage2ndarray.alpha_view(qimg) qimg.setPixel(12, 10, QtGui.qRgb(12,34,56)) assert_equal(v[10,12], 255) assert_equal(v[10,11], 0)
def getRoomFromPix(self, pos): r = 5 best_room, best_pixels = None, 0 for idx, box in enumerate(self.imageBounds): # Check to see if clicked position is inside the bounds of current image if box[0].x() < pos.x() < box[1].x() and box[0].y() < pos.y( ) < box[1].y(): # Check to see if the number of nearby pixels is greater than the current max values = qimage2ndarray.alpha_view(self.images[idx]) x, y = int(pos.x() - box[0].x()), int(pos.y() - box[0].y()) min_x, min_y = max(0, x - r), max(0, y - r) max_x, max_y = min(values.shape[0] - 1, x + r + 1), min(values.shape[1] - 1, y + r + 1) pixels = values[min_x:max_x, min_y:max_y].sum() if pixels > best_pixels: best_pixels = pixels best_room = idx return best_room
def export_ndarray(self): mask = self.mask_pixmap.toImage().convertToFormat(QImage.Format_ARGB32) return np.dstack((rgb_view(mask).copy(), alpha_view(mask).copy()))
def fillArea(self, remove_closed_contour=False, remove_only_current_color=True): # Store previous state so we can go back to it self._overlay_stack.append(self.mask_pixmap.copy()) if self.direct_mask_paint: self._offscreen_mask_stack.append(self._offscreen_mask.copy()) # We first convert the mask to a QImage and then to ndarray orig_mask = self.mask_pixmap.toImage().convertToFormat( QImage.Format_ARGB32) msk = alpha_view(orig_mask).copy() # Apply simple tresholding and invert the image msk[np.where((msk > 0))] = 255 msk = 255 - msk msk1 = np.copy(msk) if remove_closed_contour: msk1 = 255 - msk1 if remove_closed_contour: if remove_only_current_color: the_mask = np.ones(msk1.shape[:2], np.uint8) * 255 # Initial mask fullmask = self.export_ndarray_noalpha( ) # Get the colored version reds, greens, blues = fullmask[:, :, 0], fullmask[:, :, 1], fullmask[:, :, 2] cur_col = list(self.brush_fill_color.getRgb() )[:-1] # Only current color is considered # So that fill happens only for this specific color the_mask[ np.isclose(reds, cur_col[0], atol=PIXMAP_CONV_BUG_ATOL) & np.isclose(greens, cur_col[1], atol=PIXMAP_CONV_BUG_ATOL) & np.isclose(blues, cur_col[2], atol=PIXMAP_CONV_BUG_ATOL)] = 0 else: the_mask = np.zeros(msk1.shape[:2], np.uint8) else: the_mask = cv2.bitwise_not(np.copy(msk)) the_mask = cv2.copyMakeBorder(the_mask, 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0) # Fill the contour seed_point = (int(self.lastCursorLocation.x()), int(self.lastCursorLocation.y())) cv2.floodFill(msk1, the_mask, seed_point, 0, 0, 1) # We paint in only the newly arrived pixels (or remove the pixels in the contour) if remove_closed_contour: paintin = msk1 else: paintin = msk - msk1 # This is fill case # Take original pixmap image: it has two components, RGB and ALPHA new_img = np.dstack((rgb_view(orig_mask), alpha_view(orig_mask))) # Fill the newly created area with current brush color if not remove_closed_contour: new_img[np.where( (paintin == 255))] = list(self.brush_fill_color.getRgb()) else: new_img[np.where((paintin == 0))] = (0, 0, 0, 0) # Erase new_qimg = array2qimage(new_img) # In case of direct drawing, need to update the offscreen mask as well if self.direct_mask_paint: omask = byte_view(self._offscreen_mask).copy() omask = omask.reshape(omask.shape[:-1]) if not remove_closed_contour: tc = self.d_rgb2gray[self.brush_fill_color.name()] omask[np.where((paintin == 255))] = tc else: omask[np.where((paintin == 0))] = 0 self._offscreen_mask = QImage(omask.data, omask.shape[1], omask.shape[0], omask.strides[0], QImage.Format_Grayscale8) # Finally update the screen stuff self.mask_pixmap = QPixmap.fromImage(new_qimg) self._overlayHandle.setPixmap(self.mask_pixmap)