Example #1
0
 def finish(self):
     """
     To be called when the algorithm finished successfully.
     """
     self.__finished = True
     self.onFinished()
     logging.log("Finished image generation")
Example #2
0
    def step(self):
        """
        Draw a random shape onto the image and evaluate the detected class.
        """

        self.createRandomShape()
        classification = api.classifyPILImage(self.image)
        self._countApiCall()

        classId = ''
        confidence = 0

        if len(self._targetClasses) == 0:
            # no specific target class is specified
            # use the one with the highest confidence (already sorted by API)
            classId = str(classification[0]["class"])
            confidence = classification[0]["confidence"]
        else:
            for c in classification:
                if c["class"] in self._targetClasses:
                    classId = c["class"]
                    confidence = c["confidence"]
                    break
                    # break as soon as a matching class is found
                    # confidences are sorted by the api,
                    # so we've selected the highest possible confidence here
            classId = self._targetClasses[random.randrange(
                0, len(self._targetClasses))]

        logging.log(confidence)
        if confidence > 0.9:
            self.finish()
        self.onStep([(classId, confidence)])
Example #3
0
 def crossover(self):
     logging.log("EA: crossover")
     for j in range(len(self.population) - 1):
         colorsFirst = self.population[0 + j]["colors"]
         colorsSecond = self.population[1 + j]["colors"]
         img = Image.new('RGB', (64, 64), color='black')
         draw = ImageDraw.Draw(img)
         positions = [
             ((0, 0), (32, 32)),
             ((32, 0), (64, 32)),
             ((0, 32), (32, 64)),
             ((32, 32), (64, 64)),
         ]
         colors = [
             colorsFirst[0], colorsFirst[1], colorsSecond[2],
             colorsSecond[3]
         ]
         for i in range(4):
             draw.rectangle(positions[i], fill=colors[i])
         self.population.append({
             "image": img,
             "confidence": 0,
             "colors": colors,
             "class": ""
         })
Example #4
0
    def step(self):
        if not self.initialized:
            self.initPopulation(self.initialPopulationSize)
            if self.evalFitness():
                return
            self.selection(self.targetPopulationSize, 1)
            self.matchCount = self.getCountThatMatch(self.targetConfidence)
            self.initialized = True

        self.crossover()
        self.mutate(self.targetConfidence)
        if self.evalFitness():
            return
        self.__currentGeneration += 1
        self.selection(self.targetPopulationSize, 1)

        # avoid local maxima by adding new individuals when no improvement
        newMatchCount = self.getCountThatMatch(self.targetConfidence)
        if newMatchCount == self.matchCount:
            self.addRandomImage()
            logging.log("EA: add new individual (avoid local maxima)")
        self.matchCount = newMatchCount

        if self.matchCount > self.targetPopulationSize:
            self.finish()
Example #5
0
    def step(self, forTest=False):
        """
        Simulate a step of the evolutionary algorithm
        """
        if not self.initialized:
            self.initPopulation(self.initialPopulationSize)
            if self.evalFitness(forTest):
                return
            self.selection(self.targetPopulationSize, 2)
            self.matchCount = self.getCountThatMatch(self.targetConfidence)
            self.initialized = True

        self.crossover()
        self.mutate(self.targetConfidence)
        if self.evalFitness(forTest):
            return
        self.__currentGeneration += 1
        self.selection(self.targetPopulationSize, 2)

        # avoid local maxima by adding new individuals when no improvement
        newMatchCount = self.getCountThatMatch(self.targetConfidence)
        if newMatchCount == self.matchCount:
            self.addRandomImage()
            logging.log("EA: add new individual (avoid local maxima)")
        self.matchCount = newMatchCount

        if self.matchCount > self.targetPopulationSize:
            self.finish()
Example #6
0
 def selection(self, bestCount, sameClassCount):
     """
     Select best individuals from population according to the same class count (used for crossover)
     """
     print("doing selection")
     logging.log("EA: selection")
     # sort by confidence
     self.population.sort(key=lambda individual: individual["confidence"],
                          reverse=True)
     classesContained = []
     selectedPopulation = []
     for individual in self.population:
         # limit count of individuals with same class
         if (classesContained.count(individual["class"]) < sameClassCount):
             # do not take individuals with confidence > 90 %
             if (not any(selectedIndividual["confidence"] >=
                         self.targetConfidence and
                         selectedIndividual["class"] == individual["class"]
                         for selectedIndividual in selectedPopulation)):
                 selectedPopulation.append(individual)
             classesContained.append(individual["class"])
     self.population = selectedPopulation
     # reduce individuals -> reduce API calls
     if sameClassCount is 2:
         # del population[int(INITIAL_POPULATION/2):]
         print("no individuals deleted from selection")
     elif sameClassCount is 1:
         del self.population[bestCount:]
Example #7
0
 def mutate(self, confidence):
     """
     Mutate each individual in the population by mutating random color and polygon points
     """
     print("doing mutation of crossover images")
     logging.log("EA: mutation")
     population_size = len(self.population)
     for i in range(population_size):
         # use only for confidence < 90% and crossovered individuals
         if (self.population[i]["confidence"] < self.targetConfidence
                 and self.population[i]["lastCrossover"] is True):
             img = Image.new('RGB', (64, 64), color='black')
             draw = ImageDraw.Draw(img)
             # mutate colors
             colors = self.population[i]["colors"]
             colors = list(
                 map(
                     lambda color: (color[0] + random.randint(
                         -self.colorMutationRate, self.colorMutationRate
                     ), color[1] + random.randint(
                         -self.colorMutationRate, self.colorMutationRate
                     ), color[2] + random.randint(-self.colorMutationRate,
                                                  self.colorMutationRate)),
                     colors))
             # mutate shapes
             shapes = self.population[i]["shapes"]
             newShapes = []
             for shape in shapes:
                 # add or delete point
                 if random.random() < 0.5:
                     idx = random.randrange(0, len(shape))
                     if (len(shape) > self.shapePolygonPointCount
                             and random.random() < 0.5):
                         del shape[idx]
                     else:
                         shape.insert(idx, self.randomCoord())
                 # mutate point
                 shape = list(
                     map(
                         lambda x:
                         (self.mutateCoord(x[0]), self.mutateCoord(x[1])),
                         shape))
                 newShapes.append(shape)
             self.drawShapes(draw, colors, newShapes)
             self.population[i] = {
                 "image": img,
                 "confidence": 0,
                 "colors": colors,
                 "class": "",
                 "shapes": newShapes,
                 "lastCrossover": False
             }
             self.__totalMutationCount += 1
Example #8
0
def __sendToApi(data):
    """
    Classify an image using the API.
    data needs to contain the bytes of a png formatted image.
    """
    key = config.get('API', 'key')
    url = config.get('API', 'url')
    success = False
    resJson = None
    printedRateLimitingMessage = False
    with __lock:
        while not success:
            try:
                res = requests.post(
                    url,
                    data={'key': key},
                    files={'image': data}
                )
                resJson = res.json()
                success = True
            except JSONDecodeError:
                if not printedRateLimitingMessage:
                    logging.log('API: Rate limiting detected, retrying...')
                    printedRateLimitingMessage = True
                time.sleep(1)
            except ValueError:
                if not printedRateLimitingMessage:
                    logging.log('API: Rate limiting detected, retrying...')
                    printedRateLimitingMessage = True
                time.sleep(1)
            except Exception as e:
                logging.log('API: Unexpected Error: ' +
                            str(e) + ', retrying...')
                time.sleep(1)
    return resJson
Example #9
0
    def mutate(self, confidence):
        logging.log("EA: mutation")
        oldPopulationSize = len(self.population)
        for j in range(oldPopulationSize):
            img = Image.new('RGB', (64, 64), color='black')
            draw = ImageDraw.Draw(img)
            positions = [
                ((0, 0), (32, 32)),
                ((32, 0), (64, 32)),
                ((0, 32), (32, 64)),
                ((32, 32), (64, 64)),
            ]
            colors = self.population[j]["colors"]
            if (self.population[j]["confidence"] < confidence):
                # change the color of a random square
                rect = random.randint(0, 3)
                colors[rect] = (
                    colors[rect][0] + random.randint(-self.colorMutationRate,
                                                     self.colorMutationRate),
                    colors[rect][1] + random.randint(-self.colorMutationRate,
                                                     self.colorMutationRate),
                    colors[rect][2] + random.randint(-self.colorMutationRate,
                                                     self.colorMutationRate),
                )

            for i in range(4):
                draw.rectangle(positions[i], fill=colors[i])

            self.population.append({
                "image": img,
                "confidence": 0,
                "colors": colors,
                "class": ""
            })
            # delete old
        del self.population[:oldPopulationSize]
Example #10
0
 def start(self):
     super().start()
     self.__startTime = time.time()
     logging.log("Started image generation")
Example #11
0
    def crossover(self):
        """
        Crossover between individuals with same classes from the population.
        Sort duplicates with same classes like [vorfahrt52%, vorfahrt35%]
        """
        print("doing crossover")
        seen = []  # helper list for found classes
        duplicates = []
        # append one individual from every class
        for individual in self.population:
            if individual["class"] not in seen:
                duplicates.append([individual])
                seen.append(individual["class"])
        # print(duplicates)
        # append other individuals from same class
        for index, entry in enumerate(duplicates):
            for individual in self.population:
                if (individual not in entry
                        and individual["class"] == entry[0]["class"]):
                    duplicates[index] = duplicates[index] + [individual]
        # filter duplicates for crossover by confidence and length
        # crossover makes only sense for at least two individuals
        duplicates = [
            entry for entry in duplicates
            if len(entry) > 1 and entry[0]["confidence"] < 0.90
        ]
        beforeCrossover = duplicates  # for testing function
        afterCrossover = []
        newImagesAppended = 0
        # crossover by adding polygons points
        for entry in duplicates:
            # remove every other point
            # shape = shape[1::2]
            image = Image.new('RGB', (64, 64))
            draw = ImageDraw.Draw(image)
            shapes = entry[0]["shapes"] + entry[1]["shapes"]
            colors = entry[0]["colors"] + entry[1]["colors"][1:]
            self.drawShapes(draw, colors, shapes)
            newIndividual = {
                "image": image,
                "confidence": 0,
                "colors": colors,
                "class": "",
                "shapes": shapes,
                "lastCrossover": True
            }
            afterCrossover.append(newIndividual)
            self.population.append(newIndividual)
            # add second crossover child
            image = Image.new('RGB', (64, 64))
            draw = ImageDraw.Draw(image)
            shapes = entry[1]["shapes"] + entry[0]["shapes"]
            colors = entry[1]["colors"] + entry[0]["colors"][1:]
            self.drawShapes(draw, colors, shapes)
            newIndividual = {
                "image": image,
                "confidence": 0,
                "colors": colors,
                "class": "",
                "shapes": shapes,
                "lastCrossover": True
            }
            afterCrossover.append(newIndividual)
            self.population.append(newIndividual)
            newImagesAppended += 2

        print("crossover, appended images: " + str(newImagesAppended))
        logging.log("EA: crossover, add " + str(newImagesAppended) +
                    " individuals")

        # for testing crossover method
        return {"before": beforeCrossover, "after": afterCrossover}