def step(self, x, y, direction, brightness): """ step is called many times while iterating over the loaded bitmap in each step we calculate a circle based on position x,y with given brightness in the bitmap. direction is a direction vector indicating what direction we are moving in. calculate a new circle in the circle generation process :param x: x pos in bitmap that calculation should be based on :param y: y pos in bitmap that calculation should be based on :param direction: in what direction are we moving? :param brightness: gray value in the bitmap at x,y :return: potentially modified step size """ r = Mapping.linexp(brightness, self.minBrightness, self.maxBrightness, self.maxRadius, self.minRadius) if not r: r = self.minRadius stepsize = int( Mapping.linlin(brightness, self.minBrightness, self.maxBrightness, self.minStepSize, self.maxStepSize)) if not self.clipToBitmap or (self.clipToBitmap and not Circle( x, y, r).edges(self.width, self.height)): item = QGraphicsEllipseItem(x - r, y - r, r * 2, r * 2) pen = QPen() pen.setWidth(self.strokeWidth) item.setPen(pen) self.group.addToGroup(item) return max(int(stepsize), 1)
def step(self, x, y, direction, brightness): """ step is called many times while iterating over the loaded bitmap in each step we calculate a squiggle based on position x,y with given brightness in the bitmap. direction is a direction vector indicating what direction we are moving in. calculate a new squiggle in the circle generation process :param x: x pos in bitmap that calculation should be based on :param y: y pos in bitmap that calculation should be based on :param direction: in what direction are we moving? :param brightness: gray value in the bitmap at x,y :return: potentially modified step size """ stepSize = Mapping.linexp(brightness, 0, 255, self.minStepSize, self.maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / self.detail) self.previous_stepsize = stepSize amplitudeSize = Mapping.linlin(brightness, 0, 255, self.strength, 0) if self.prevPos is None: self.path = QPainterPath() self.path.moveTo(x, y) self.prevPos = np.array([[ x, ], [ y, ]]) else: newPos = np.array([[ x, ], [ y, ]]) dirx = direction[0][0] diry = direction[1][0] ortho_dir = np.array([[-diry], [dirx] ]) * self.disturbance_direction disturbance = ortho_dir * amplitudeSize disturbedPos = (self.prevPos + newPos) / 2 + disturbance if not self.clipToBitmap or (self.clipToBitmap and not Circle( x, y, amplitudeSize).edges(self.width, self.height)): self.path.quadTo(disturbedPos[0][0], disturbedPos[1][0], newPos[0][0], newPos[1][0]) else: self.path.moveTo(newPos[0][0], newPos[1][0]) self.prevPos = newPos self.disturbance_direction = -self.disturbance_direction return max(int(stepSize), 1)
def makeBubbles(self, image): """ helper method for bubblification (contains the actual calculations) :param image: :return: """ self.parent.progressBarBubblify.setVisible(True) self.parent.application.processEvents() minBrightness = self.parent.minBrightnessBubblify.value() maxBrightness = self.parent.maxBrightnessBubblify.value() minCircleRadius = self.parent.minRadiusBubblify.value() maxCircleRadius = self.parent.maxRadiusBubblify.value() invertColors = self.parent.invertColorsBubblify.checkState( ) == Qt.Checked minProbability = self.parent.minProbabilityBubblify.value() maxProbablity = self.parent.maxProbabilityBubblify.value() radiustolerance = self.parent.radiusToleranceBubblify.value() strokeWidth = 1 # remove existing data on this layer self.removeOldGraphicsItems() # first add seeding points print("Seeding points") spots = [] circles = [] for x in range(image.width()): for y in range(image.height()): grayvalue = qGray(image.pixel(x, y)) if invertColors: grayvalue = 255 - grayvalue if minBrightness < grayvalue < maxBrightness: probability = Mapping.linexp(grayvalue, 0, 255, maxProbablity / 100, minProbability / 100) addNow = random() < probability if addNow: spots.append([x, y]) print("Optimizing {0} points".format(len(spots))) # next find out radii we can use that avoid overlap print("Analyzing radii") if len(spots): tree = spatial.KDTree(spots) for center in spots: x = center[0] y = center[1] grayvalue = qGray(image.pixel(x, y)) proposed_radius = Mapping.linexp(grayvalue, minBrightness, maxBrightness, minCircleRadius, maxCircleRadius) nearest_neighbor = tree.query(np.array([[x, y]]), 2) # print("{0} nearest to {1}".format(nearest_neighbor, [x,y])) if nearest_neighbor: try: distance = nearest_neighbor[0][0][1] maxradius = np.floor(distance / 2) minimum = min(proposed_radius, maxradius) # print("Using minimum of proposed {0} and max {1}".format(proposed_radius, maxradius)) if minimum >= proposed_radius * radiustolerance: circles.append((x, y, minimum)) except: print("weird nearest neighbor: ", nearest_neighbor) print("Visualize") # next, visualize group = QGraphicsItemGroup() for c in circles: x = c[0] y = c[1] r = c[2] item = QGraphicsEllipseItem(x - r, y - r, r * 2, r * 2) pen = QPen() pen.setWidth(strokeWidth) item.setPen(pen) group.addToGroup(item) self.addNewGraphicsItems(group) self.parent.progressBarBubblify.setVisible(False)
def makeSquiggles(self, image): """ actual calculations :param image: bitmap to squigglify :return: """ noOfLines = self.parent.noOfLines.value() height = image.height() width = image.width() amplitude = self.parent.strength.value() strokeWidth = self.parent.lineWidth.value() detail = self.parent.detail.value() invertColors = self.parent.invertColors.checkState() == Qt.Checked verticalSquiggles = self.parent.verticalSquiggles.checkState( ) == Qt.Checked maxBrightness = self.parent.maxBrightness.value() minBrightness = self.parent.minBrightness.value() self.removeOldGraphicsItems() group = QGraphicsItemGroup() finalRow = False minStepSize = self.parent.minStepSize.value() maxStepSize = self.parent.maxStepSize.value() # TODO: too much code duplication! path = QPainterPath() if not verticalSquiggles: scaledystep = max(1, height / noOfLines) for y in frange(0, height, scaledystep): if fabs(y - height) < 1e-3 or y >= height: finalRow = True x = 0 disturbance_direction = -1 prevX = 0 prevY = y while x < width: disturbance_direction = -disturbance_direction grayvalue = qGray(image.pixel(x, y)) if invertColors: grayvalue = 255 - grayvalue stepSize = Mapping.linexp(grayvalue, 0, 255, minStepSize, maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / detail) amplitudeSize = Mapping.linlin(grayvalue, 0, 255, amplitude, 0) if x == 0: path = QPainterPath() path.moveTo(x, y) x = prevX + stepSize newY = prevY + amplitudeSize * disturbance_direction if minBrightness <= grayvalue <= maxBrightness: path.quadTo((prevX + x) / 2, newY, x, prevY) else: path.moveTo(x, prevY) if x >= width: item = QGraphicsPathItem(path) pen = QPen() pen.setWidth(strokeWidth) item.setPen(pen) group.addToGroup(item) prevX = x prevY = y if finalRow: break else: scaledxstep = max(1, width / noOfLines) for x in frange(0, width, scaledxstep): if fabs(x - width) < 1e-3 or x >= width: finalRow = True y = 0 disturbance_direction = -1 prevX = x prevY = 0 while y < height: disturbance_direction = -disturbance_direction grayvalue = qGray(image.pixel(x, y)) if invertColors: grayvalue = 255 - grayvalue stepSize = Mapping.linexp(grayvalue, 0, 255, minStepSize, maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / detail) amplitudeSize = Mapping.linlin(grayvalue, 0, 255, amplitude, 0) if y == 0: path = QPainterPath() path.moveTo(x, y) y = prevY + stepSize newX = prevX + amplitudeSize * disturbance_direction if minBrightness <= grayvalue <= maxBrightness: path.quadTo(newX, (prevY + y) / 2, prevX, y) else: path.moveTo(x, prevY) if y >= height: item = QGraphicsPathItem(path) pen = QPen() pen.setWidth(strokeWidth) item.setPen(pen) group.addToGroup(item) prevX = x prevY = y if finalRow: break self.addNewGraphicsItems(group)