///
/// Load a bitmap and create ASCII art from it using linear optimization
///
///
private void ASCIILinearOptimization(int blockSize)
{
char[] tiles = new char[] { '■', '@', '#', '?', '!', 'x', '-', ',', '.', ' ' };
double[] tilesWeight = new double[] { 1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.3, 0.2, 0.1, 0.0 };
double[,] image = GetBlockBrightness("./Input/Lena.jpg", blockSize);
CpModel model = new CpModel();
// variables
Dictionary variableSet = new Dictionary();
// cost function
LinearExprBuilder cost = LinearExpr.NewBuilder();
// for each block
for (int i = 0; i < image.GetLength(0); i++)
{
for (int j = 0; j < image.GetLength(1); j++)
{
// create variables for each combination block-character
List forOneSquare = new List();
for (int c = 0; c < tiles.Length; c++)
{
string varName = "x_" + i + "_" + j + "_" + c;
IntVar xijc = model.NewIntVar(0, 1, varName);
variableSet.Add(varName, xijc);
forOneSquare.Add(xijc);
// weight has to be integer !!
long weight = (long)(100 * Math.Abs(image[i, j] - tilesWeight[c]));
// add to cost function
cost.AddTerm(xijc, weight);
}
// for each square we can pick only one tile
model.Add(LinearExpr.Sum(forOneSquare) == 1); // = one constraint per block
}
}
// minimize cost function with given constraints
model.Minimize(cost);
CpSolver solver = new CpSolver();
CpSolverStatus status = solver.Solve(model);
// if successfull solving print result
if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
{
// check each variable
for (int i = 0; i < image.GetLength(0); i++)
{
for (int j = 0; j < image.GetLength(1); j++)
{
for (int c = 0; c < tiles.Length; c++)
{
string varName = "x_" + i + "_" + j + "_" + c;
// if variable is true, print corresponding character
if (solver.Value(variableSet[varName]) == 1)
Console.Write(tiles[c]);
}
}
Console.WriteLine();
}
}
else
{
Console.WriteLine("No solution found.");
}
}