Converting a bitmap to an matrix - c#

I've been trying to convert a bitmap object to a matrix of int.
I drew the letter 'C' in paint on a blank white sheet and the program was supposed to initialize the arr in place (x,y) with '0' if the pixel in the Bitmap object in the same position (x,y) is white and correspondingly '1' if it were a black pixel.
I wrote the following code:
static void Main(string[] args)
{
Bitmap arie = new Bitmap(#"C:\Users\User\Desktop\letter.bmp");
object [,] arr = new object[arie.Width, arie.Height];
int min=1000,counter=1;
for (int i = 0; i < arr.GetLength(0) - 1; i++)
{
for (int j = 0; j < arr.GetLength(1) - 1; j++)
{
if (arie.GetPixel(i, j).ToArgb() == Color.White.ToArgb())
{
arr[i, j] = 0;
}
else
arr[i, j] = 1;
}
}
for (int i = 1; i < arr.GetLength(0) - 2; i++)
{
for (int j = 1; j < arr.GetLength(1) - 2; j++)
{
Console.Write(arr[i, j]);
}
Console.WriteLine();
}
}
at the end the letter 'C' that I drew came out like this:
http://teachers.web.cern.ch/teachers/archiv/hst2000/teaching/expt/wavesand/image39.gif
Can anyone seem to recognize the issue?

The main issue is that when you are outputting the array to the console, you are traversing it by columns, rather than rows. That is why your array appears to be rotated by 90 degrees.
If in the second looping portion (where you are outputting to the console), you swap the inner and outer loops, you should see better results.
I also agree with the other comments that:
1) If you want better performance, use the LockBits/UnlockBits method of accessing the Bitmap
2) Your loop indexing is out of whack
If you use x and y instead of i and j, it will help you recognize when you're making these kind of mistakes.
Try this:
static void Main(string[] args)
{
Bitmap arie = new Bitmap(#"C:\Users\User\Desktop\letter.bmp");
object [,] arr = new object[arie.Width, arie.Height];
int min=1000,counter=1;
for (int i = 0; i < arie.Width; i++)
{
for (int j = 0; j < arie.Height; j++)
{
if (arie.GetPixel(i, j).ToArgb() == Color.White.ToArgb())
{
arr[i, j] = 0;
}
else
arr[i, j] = 1;
}
}
for (int y = 0; y < arie.Height; y++)
{
for (int x = 0; x < arie.Width; x++)
{
Console.Write(arr[x, y]);
}
Console.WriteLine();
}
}

Related

How to populate 2D array with char array in C#

I'm trying to fill a 2D char array with characters form a char array
I have tried this code but not finding the problem
public void FillArray(char[,] array, char[] values)
{
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
for (int k = 0; k < values.Length; k++)
{
array[i, j] = values[k];
}
}
}
}
Your first for loop is responsible for iteration over first dimension of array (i) It's okay.
Your second for loop is responsible for iteration over second dimension of array (j). It's okay.
Your third loop is responsible for iteration over char values array (k) Here's your bug.
For a given set of values of i and j which represents dimensions indexes of array, your function iterates through all positions of values array. So for each k value i and j values remain unchanged. Therefore you sequentially put all the values of values array (k+1)times into the same cell of two dimension array, ultimately leaving it with value of values[values.Length] as it is the highest possible value of k in the most nested loop.
I'd suggest solution similar to what #adv12 has proposed with slight modification as I am not sure if the k value would be 0 during first iteration of the nested for loop. It is also more readable IMO.
int k = 0;
public void FillArray(char[,] array, char[] values)
{
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = values[k];
k++
if (k >= values.Length)
{
k = 0;
}
}
}
}
Here's my best guess at what you want based on your comments:
int k = 0;
public void FillArray(char[,] array, char[] values)
{
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = values[k++];
if (k >= values.Length)
{
k = 0;
}
}
}
}

Is there a way to increase the stack size in c#?

I'm coming back to programming after having done none for several years, and created a Sudoku game to get my feet wet again. I've written a recursive function to brute-force a solution, and it will do so for simple board states, but runs into a stack overflow most of the time for more complicated board states. I know that this could be averted using loops or a more efficient algorithm, but since this is for the sake of learning I want to know how to allocate more memory to the stack (acknowledging this isn't the best solution to the problem).
An answer here: How to change stack size for a .NET program? that recommends using a thread with more memory allocated isn't working, as from what I can read .NET 4.0 will not let you increase a thread's maximum allocated memory beyond the default.
Another solution recommends using EDITBIN.EXE, but I am new to Visual Studio and have not found an explanation I understand of how to do so.
Similarly, I've found that you can use a .def file to indicate a larger default stack size, but have not found an explanation I understand of how to create/implement one.
Can anyone offer newbie-level explanations of either EDITBIN.EXE or .def file implementations, or offer another way to increase the stack size?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Sudoku
{
//object keeps track of the value of all numbers currently on the board using an array
class BoardState
{
int testcount = 1;
//3d array of ints representing all values on the board, represted as region, column, row
int[,,] boardVals;
//3d array of bools representing if a number is immutable (true cannot be changed, false can be)
bool[,,] fixedVals;
//create a blank board if no initial values are provided
public BoardState()
{
boardVals = new int[9, 3, 3];
fixedVals = new bool[9, 3, 3];
}
//create a board with the listed initial values as immutable
public BoardState(int[,,] inputVals)
{
boardVals = inputVals;
fixedVals = new bool[9,3,3];
for (int i = 0; i < 9; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
if (boardVals[i, j, k] > 0) fixedVals[i, j, k] = true;
}
//update the state of the board using the coordinates of a single value
//**note** method has not been implemented and tested yet
public void updateState(int region, int column, int row, int val)
{
if (!fixedVals[region, column, row])
{
boardVals[region, column, row] = val;
}
}
//update the state of the board to match the state of another board
public void updateState(int[,,] newState)
{
boardVals = newState;
}
public int[,,] getVals()
{
return boardVals;
}
public bool[,,] getFixed()
{
return fixedVals;
}
//set all non-zero values to be immutable
public void setFixed()
{
for (int i = 0; i < 9; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) {
if (boardVals[i, j, k] != 0)
fixedVals[i, j, k] = true;
else
fixedVals[i, j, k] = false;
}
}
//test method
public void testState()
{
for (int i = 0; i < 9; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
Console.WriteLine(boardVals[i, k, j]);
}
//accepts a 3d array representing the current board state.
//returns a 3d bool array denoting whether any region, row, or column is invalid (true=invalid)
//first value of array designates the region, row, or column respectively
//second value designates which of those is invalid
public bool[,] validateBoard()
{
bool[,] valid = new bool[3, 9];
int[,] rows = makeRows(boardVals);
int[,] cols = makeCols(boardVals);
//compare each value in each row to each other value in that row
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (rows[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && rows[i, j] == rows[i, k])
valid[1, i] = true;
}
}
}
}
//compare each value in each column to each other value in that column
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (cols[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && cols[i, j] == cols[i, k])
valid[2, i] = true;
}
}
}
}
//compare each value in each region to each other value in that region
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
//only validate an entry if it has been assigned a value
if (boardVals[i, j, k] != 0)
{
for (int l = 0; l < 3; l++)
{
for (int m = 0; m < 3; m++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (!(l == j && m == k) && boardVals[i, j, k] == boardVals[i, l, m])
valid[0, i] = true;
}
}
}
}
}
}
return valid;
}
public bool isValid()
{
bool retFlag = true;
bool[,] valid = new bool[3, 9];
int[,] rows = makeRows(boardVals);
int[,] cols = makeCols(boardVals);
//for (int i = 0; i < 9; i++)
// for (int j = 0; j < 3; j++)
// for (int k = 0; k < 3; k++)
// Console.Write(boardVals[i, j, k]);
//compare each value in each row to each other value in that row
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (rows[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && rows[i, j] == rows[i, k])
{
retFlag = false;
}
}
}
}
}
//compare each value in each column to each other value in that column
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (cols[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && cols[i, j] == cols[i, k])
{
retFlag = false;
}
}
}
}
}
//compare each value in each region to each other value in that region
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
//only validate an entry if it has been assigned a value
if (boardVals[i, j, k] != 0)
{
for (int l = 0; l < 3; l++)
{
for (int m = 0; m < 3; m++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (!(l == j && m == k) && boardVals[i, j, k] == boardVals[i, l, m])
{
retFlag = false;
}
}
}
}
}
}
}
return retFlag;
}
//returns an array of all the values in each row
public int[,] makeRows(int[,,] boardState)
{
int[,] rows = new int[9, 9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
rows[i, j] = boardState[j / 3 + ((i / 3) * 3), j % 3, i - ((i / 3) * 3)];
return rows;
}
//returns an array of all values in each column
public int[,] makeCols(int[,,] boardState)
{
int[,] cols = new int[9, 9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
cols[i, j] = boardState[((j / 3) * 3) + (i / 3), i - ((i / 3) * 3), j % 3];
return cols;
}
//update the board state to a state read in from a file
public void updateFromFile(Stream update)
{
int[,,] newVals = new int[9, 3, 3];
int[,,] newFixed = new int[9, 3, 3];
StreamReader file = new StreamReader(update);
for (int i = 0; i < 9; i++){
for (int j = 0; j < 3; j++){
for (int k = 0; k < 3; k++){
boardVals[i, j, k] = (int)char.GetNumericValue((char)file.Read());
}
}
}
for (int i = 0; i < 9; i++){
for (int j = 0; j < 3; j++){
for (int k = 0; k < 3; k++){
fixedVals[i, j, k] = (0 != ((int)char.GetNumericValue((char)file.Read())));
}
}
}
file.Close();
}
public void Solve(int entry, int val)
{
Console.WriteLine("This is call number " + ++testcount);
//returns if all values are filled and valid
if (entry == 81)
{
Console.WriteLine("Solved!");
return;
}
//creating reference coordinates based on entry value
int reg = entry / 9;
int col = (entry - (reg * 9)) % 3;
int row = (entry - (reg * 9)) / 3;
//if current entry being checked is a fixed value, go the next value
if (!fixedVals[reg, row, col])
{
Console.WriteLine("");
Console.WriteLine("Making an attempt at entry " + entry + " using value " + val);
Console.WriteLine("This entry is at region " + reg + ", col " + col + ", row " + row);
//assign entry the value to be tested
boardVals[reg, row, col] = val;
//if the value is valid, go to the next entry
if (isValid())
{
Console.WriteLine("Entry Valid at " + entry);
val = 1;
entry++;
Console.WriteLine("Trying the next entry at " + entry);
Solve(entry, val);
}
//if the value is invlid and all 9 values have not been tried,
//increment value and call again at same entry
if (!isValid() && val < 9)
{
Console.WriteLine("Entry Invalid at " + entry + " with value " + val);
++val;
Console.WriteLine("Trying again with value " + val);
Solve(entry, val);
}
//if the value in invalid and all 9 values have been tried,
//zero out the entry and go back to the previous non-fixed entry
if (!isValid() && val == 9)
{
do
{
boardVals[reg, row, col] = 0;
Console.WriteLine("Reached Value 9 and was still invalid");
--entry;
Console.WriteLine("Trying again at entry " + entry);
Console.WriteLine("The value at that entry is " + boardVals[reg, row, col]);
reg = entry / 9;
col = (entry - reg * 9) % 3;
row = (entry - reg * 9) / 3;
if (fixedVals[reg, row, col])
Console.WriteLine("But that's a fixed value, so I'll go back one more");
Console.WriteLine("");
} while (boardVals[reg, row, col] == 9 || fixedVals[reg, row, col]);
val = boardVals[reg, row, col] + 1;
Solve(entry, val);
}
}
else Solve(++entry, val);
}
}
}
The big bad warning
If you use recursion in a program and reach a point where having a StackOverflowException is an actual threat, please do not consider increasing the stack size as a valid solution.
If you encounter a StackOverflowException you are doing something very wrong; you should instead be using a Stack<T> for depth-first processing, or a Queue<T> for breadth-first processing. Example.
The solution
This can be achieved by using editbin.exe, which is installed with this package;
Find the location of editbin.exe, mine was located at C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\editbin.exe, I would suggest using Everything by voidtools in lieu of Microsoft's awful search to find this.
Set the stack size manually
Navigate to your bin folder and execute the following:
"<full path of editbin.exe>" /stack:<stack size in bytes, decimal> <your executable name>
For example I executed this:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\EDITBIN.EXE" /stack:2097152 ExampleProgram.exe
Which set the stack reserve size to 2MB.
With this I was capable of reaching twice the recursion level; (1MB stack reserve on left, 2MB stack reserve on right).
Set the stack size automatically
Right click on your project and select 'Options', then click on 'Build Events' and add the following to your post-build events:
"<full path of editbin.exe>" /stack:<stack size in bytes, decimal> "$(TargetPath)"
For example I added
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\EDITBIN.EXE" /stack:2097152 "$(TargetPath)"
This will run editbin.exe every time you build your executable.
Note: You will see a lot lower level of recursion reached when running your program from Visual Studio as you will from running it explicitly via explorer or cmd. You will still however see a 2x increase in the level of recursion met if moving from a 1MB stack reserve to a 2MB stack reserve.
Perhaps set the Stack Reserve Size in Visual Studio:
Project -> Properties -> Configuration Properties -> Linker -> System -> Stack Reserve Size
This can also be done via the command-line or programatically when a thread is created:
https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2017

3X3 Median Filtering in c# but not working?

Really I'm trying to apply 3X3 Median Filtering by C# and depending on my understanding the concepts of Median Filtering I wrote the following code but when I'm running it the Form hangs. I think have some problem in the last nested for loop but i don't know where is the error or the wrong in applying the Median concepts!
public static Bitmap MedianFiltering(Bitmap bm)
{
List<int> termsList = new List<int>();
Bitmap res, temp;
Color c;
int counter = 0;
//Convert to Grayscale
for (int i = 0; i < bm.Width; i++)
{
for (int j = 0; j < bm.Height; j++)
{
c = bm.GetPixel(i, j);
byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
bm.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
temp = bm;
//applying Median Filtering
for (int i = 0; i <= temp.Width - 3; i++)
for (int j = 0; j <= temp.Height - 3; j++)
{
for (int x = i; x <= i + 2; x++)
for (int y = j; y <= j + 2; y++)
{
c = temp.GetPixel(x, y);
termsList.Add(c.R);
counter++;
}
int[] terms = termsList.ToArray();
Array.Sort<int>(terms);
Array.Reverse(terms);
int color = terms[4];
temp.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
counter = 0;
}
res = temp;
return res;
}
Thanks.
You are not clearing the termsList after each pixel processing. This is causing the list to keep growing. Sorting and reversing the list will keep taking longer and longer times. This will also cause incorrect results since you only want to get the median of the 9 pixels related to the current pixel.
Simply clear the list like this:
...
int[] terms = termsList.ToArray();
termsList.Clear();
...
UPDATE:
I did more optimization for the code:
public static void MedianFiltering(Bitmap bm)
{
List<byte> termsList = new List<byte>();
byte[,] image = new byte[bm.Width,bm.Height];
//Convert to Grayscale
for (int i = 0; i < bm.Width; i++)
{
for (int j = 0; j < bm.Height; j++)
{
var c = bm.GetPixel(i, j);
byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
image[i, j] = gray;
}
}
//applying Median Filtering
for (int i = 0; i <= bm.Width - 3; i++)
for (int j = 0; j <= bm.Height - 3; j++)
{
for (int x = i; x <= i + 2; x++)
for (int y = j; y <= j + 2; y++)
{
termsList.Add(image[x, y]);
}
byte[] terms = termsList.ToArray();
termsList.Clear();
Array.Sort<byte>(terms);
Array.Reverse(terms);
byte color = terms[4];
bm.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
}
}
Please note that in your original method, you returned a Bitmap. I removed this.
Please note that temp = bm; does not create a copy of the Bitmap. It is just pointing the temp variable to the same object (that is pointed by bm). So in your original method, you returned the exact object that is passed in the method parameter. To use the new method pass the Bitmap and then the bitmap it self will be modified (this is also true for your method).
This enhanced performance 4 times on my machine.
What I did is mainly read the bitmap data into a byte array instead of using the Bitmap it self to read/write data multiple times.
If you need to further enhance the performance, take a look at this question.

Filling matrix with for loops

Firstly, I fill the array with "0"s and then want to replace the first row with "1"s. Can not understand why the 2nd "for" loop fills the whole matrix with "1"s.
int i, j, array[length][width];
for (i = 0; i < length; i++) {
for (j = 0; j < width; j++) {
array[i][j] = 0;
}
}
for (i = 0; i < width; i++) {
array[0][i] = 1;
}`
I ran the code and it only filled the first row of the matrix with 1's. Try running it again.

Printing a 2D-array into "squares"

I'm trying to learn how to work with 2D-array and I can't seem to understand how to print them correctly. I want to print them in a "square" like 5x5 but all I get is one line. I've tried both WriteLine and Write and changed some of the variables in the loops but I get either an error or not the result I want to have. The code is supposed to print out a 5x5 with a random sequence of 15 numbers in each column. I get the correct numbers out of it, it's only the layout that is wrong.
static void Main(string[] args)
{
Random rnd = new Random();
int[,] bricka = new int[5, 5];
int num = 0;
int num1 = 1;
for (int i = 0; i < bricka.GetLength(1); i++)
{
num += 16;
for (int j = 0; j < bricka.GetLength(0); j++)
{
bricka[j, i] = rnd.Next(num1, num);
}
num1 += 16;
}
for (int i = 0; i < bricka.GetLength(0); i++)
{
for (int j = 0; j < bricka.GetLength(1); j++)
{
Console.Write(bricka[i, j]+ " " );
}
}
Console.ReadKey();
}
This is my print, I would like to have the the 12 under the 8 and 14 under the 12 and so on.
http://i.imgur.com/tfyRxf1.png
You need to call WriteLine() after each line, so that each line is printed on a separate line:
for (int i = 0; i < bricka.GetLength(0); i++)
{
for (int j = 0; j < bricka.GetLength(1); j++)
{
Console.Write(bricka[i, j]+ " " );
}
Console.WriteLine();
}
That would be one way of doing it, anyway.

Categories

Resources