C# find image within image with tolerance - c#

I have a function which will find a smaller image within a larger image and return me it's position. I want to set a tolerance threshold so that even if a similar (but not exactly the same) is present, it returns it's position as well.
If possible I would also want it to work if the smaller image is rotated.
I tried finding edges in the image using OpenCV, but the edges in the haystack and those in the needle image are never the exact same and it never matches.
public Point? Find(Bitmap haystack, Bitmap needle)
{
if (null == haystack || null == needle)
{
return null;
}
if (haystack.Width < needle.Width || haystack.Height < needle.Height)
{
return null;
}
var haystackArray = GetPixelArray(haystack);
var needleArray = GetPixelArray(needle);
foreach (var firstLineMatchPoint in FindMatch(haystackArray.Take(haystack.Height - needle.Height), needleArray[0]))
{
if (IsNeedlePresentAtLocation(haystackArray, needleArray, firstLineMatchPoint, 1))
{
return firstLineMatchPoint;
}
}
return null;
}
private int[][] GetPixelArray(Bitmap bitmap)
{
var result = new int[bitmap.Height][];
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
for (int y = 0; y < bitmap.Height; ++y)
{
result[y] = new int[bitmap.Width];
Marshal.Copy(bitmapData.Scan0 + y*bitmapData.Stride, result[y], 0, result[y].Length);
}
bitmap.UnlockBits(bitmapData);
return result;
}
private IEnumerable<Point> FindMatch(IEnumerable<int[]> haystackLines, int[] needleLine)
{
var y = 0;
foreach (var haystackLine in haystackLines)
{
for (int x = 0, n = haystackLine.Length - needleLine.Length; x < n; ++x)
{
if (ContainSameElements(haystackLine, x, needleLine, 0, needleLine.Length))
{
yield return new Point(x, y);
}
}
y += 1;
}
}
private bool ContainSameElements(int[] first, int firstStart, int[] second, int secondStart, int length)
{
for (int i = 0; i < length; ++i)
{
if (first[i + firstStart] != second[i + secondStart])
{
return false;
}
}
return true;
}
private bool IsNeedlePresentAtLocation(int[][] haystack, int[][] needle, Point point, int alreadyVerified)
{
//we already know that "alreadyVerified" lines already match, so skip them
for (int y = alreadyVerified; y < needle.Length; ++y)
{
if ( ! ContainSameElements(haystack[y + point.Y], point.X, needle[y], 0, needle.Length))
{
return false;
}
}
return true;
}
How can I achieve this ?

For the first: You have to define your metric for comparing two pixels
I can imagine a distance in the cube defined by RGB, or a distance in the cylinder of HSV (HSV should be more accurate)
Example:
static double GetMetric(Pixel a, Pixel b)
{
double dR = a.R - b.R;
double dG = a.G - b.G;
double dB = a.B - b.B;
return Math.Sqrt(dR * dR + dG * dG + dB * dB);
}
Then just create a window search algorithm. Create window in the haste (same size as needle). Then try every possible position of window and calculate window distance as the sum of pixel distances.
You do not recalculate whole window. While moving window to the right, just recalculate and subtract left column (the one which was removed) and calculate and add right (new) column.
Then you need to remember minimal distance and its location and just compare it.
The result is the closest window to the needle. (Depends on used metric).
A simplified example:
static void Find(Bitmap Haste, Bitmap Needle)
{
//Simplified for Haste.Height = Needle.Height
//But Haste.Width > Needle.Width
int minX = 0;
int minY = 0;
double minMetric = double.MaxValue;
//Setup first window
double actualMetric = 0;
for (int i = 0; i < Needle.Width; i++)
{
for (int j = 0; j < Needle.Height; j++)
{
actualMetric += GetMatric(Needle.GetPixel(i, j), Haste.GetPixel(i, j));
}
}
minMetric = actualMetric;
//Move window to the right
for (int i = 0; i < Haste.Width - Needle.Width; i++)
{
for (int j = 0; j < Needle.Height; j++)
{
//Subtract left column pixel
actualMetric -= GetMatric(Needle.GetPixel(i, j), Haste.GetPixel(i, j));
//Add right column pixel
actualMetric += GetMatric(Needle.GetPixel(i + Needle.Width, j), Haste.GetPixel(i + Needle.Width, j));
}
//Compare
if(actualMetric < minMetric)
{
minX = i;
minY = 0; // Because Y is fixed while simplification Haste and Needle Height
}
}
}

Related

Spiral loop for image pixel analyze (x,y) C#

I'm trying to do a pixel search in coordinates (x,y)
I need something like a function(int width, int height) that returns an array of points starting from the center.
if image has 1000x1000, i need to get [{500,500}, {501,500}, {501,501}, {500,501}, {499,501}, {499,500} ...]
Example:
Well, that was easier than I thought it would be.
static IEnumerable<Point> GetPixels(int size)
{
Point point = new Point(size/2, size/2);
yield return point;
int sign = 1;
for (int row = 1; row < size; row++)
{
// move right/left by row, and then up/down by row
for (int k = 0; k < row; k++)
{
point.Offset(sign*1, 0);
yield return point;
}
for (int k = 0; k < row; k++)
{
point.Offset(0, -sign*1);
yield return point;
}
sign *= -1;
}
// last leg to finish filling the area
for (int k = 0; k < size-1; k++)
{
point.Offset(sign*1, 0);
yield return point;
}
}
with the result (size=5)
{X=2,Y=2}
{X=3,Y=2}
{X=3,Y=1}
{X=2,Y=1}
{X=1,Y=1}
{X=1,Y=2}
{X=1,Y=3}
{X=2,Y=3}
{X=3,Y=3}
{X=4,Y=3}
{X=4,Y=2}
{X=4,Y=1}
{X=4,Y=0}
{X=3,Y=0}
{X=2,Y=0}
{X=1,Y=0}
{X=0,Y=0}
{X=0,Y=1}
{X=0,Y=2}
{X=0,Y=3}
{X=0,Y=4}
{X=1,Y=4}
{X=2,Y=4}
{X=3,Y=4}
{X=4,Y=4}
or graphically for size=50
The test code is simple enough
static void Main(string[] args)
{
foreach (var point in GetPixels(5))
{
Console.WriteLine($"{point}");
}
Console.WriteLine();
}

Imager Sharpening Kernel producing odd result C#

I'm making a small app, where you can sharpen or blur an image in C#. So far blur is working flawlessly with any kernels of all sizes. However sharpening seems to cause this weird noisy/static image (something you'd see on a TV with no signal > see below). I've recoded this multiple times, and this time I tried to copy a solution from python, in case I keep messing it up somehow. Here's what I have for sharpening:
Color[,] clone = ud.CurrentSelected._bitmap; //gets the current image as a matrix
int[,] kernel = {{0, -1, 0}, {-1, 5, -1}, {0, -1, 0}};
int offset = 1;
int size = 100; //Image is 100x100 atm
for (int x = 0; x < size - offset; x++) {
for (int y = 0; y < size - offset; y++) {
NonDisplayedColour acc = Color.Black; //custom struct for storing and casting to regular Color without bounds -> not for displaying
for (int A = 0; A < 3; A++) {
for (int B = 0; B < 3; B++) {
int deltaX = x + A - offset;
int deltaY = y + B - offset;
NonDisplayedColour pixel = ud.CurrentSelected._bitmap[deltaX, deltaY];
int r = pixel.R * kernel[A, B];
int g = pixel.G * kernel[A, B];
int b = pixel.B * kernel[A, B];
acc.R += r;
acc.G += g;
acc.B += b;
}
}
clone[x,y] = acc;
}
}
ud.CurrentSelected._bitmap = clone;
This is just the calculation part, what displays the image is this:
Bitmap b = new Bitmap(ud.CurrentSelected._bitmap.Width, ud.CurrentSelected._bitmap.Height);
for (int x = 0; x < b.Width; ++x) {
for (int y = 0; y < b.Height; ++y) {
b.SetPixel(x, y, ud.CurrentSelected._bitmap[x, y]);
}
}
The NonDisplayedColour struct is just this, if anyone wants to know:
public struct NonDisplayedColour {
public NonDisplayedColour(int r, int g, int b) {
R = r;
G = g;
B = b;
A = 255;
}
public int A;
public int R;
public int G;
public int B;
public static implicit operator Color(NonDisplayedColour c) {
return Color.FromArgb((byte) c.A, (byte) c.R, (byte) c.G, (byte) c.B);
}
public static implicit operator NonDisplayedColour(Color c) {
return new NonDisplayedColour(c.R, c.G, c.B) {A = c.A};
}
}
The end result, is the following image.
Thanks for the help in advance.
PS.: I know locking bits would be much faster, but I'm going for simplicity rather than speed and SetPixel (to me at least) is much simpler.

Optimizing my image search routine

My routine is as follows (the SpeedyBitmap class just locks each bitmap for faster pixel data access):
private static bool TestRange(int number, int lower, int upper) {
return number >= lower && number <= upper;
}
public static List<Point> Search(Bitmap toSearch, Bitmap toFind, double percentMatch = 0.85, byte rTol = 2, byte gTol = 2, byte bTol = 2) {
List<Point> points = new List<Point>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int findArea = toFind.Width * toFind.Height;
int allowedMismatches = findArea - (int)(findArea * percentMatch);
int mismatches = 0;
using (SpeedyBitmap speedySearch = new SpeedyBitmap(toSearch)) {
using (SpeedyBitmap speedyFind = new SpeedyBitmap(toFind)) {
for (int i = 0; i < speedySearch.Height - speedyFind.Height + 1; i++) {
for (int j = 0; j < speedySearch.Width - speedyFind.Width + 1; j++) {
for (int k = 0; k < speedyFind.Height; k++) {
for (int l = 0; l < speedyFind.Width; l++) {
Color searchColor = speedySearch[j + l, i + k];
Color findColor = speedyFind[l, k];
if (!TestRange(searchColor.R, findColor.R - rTol, findColor.R + rTol) ||
!TestRange(searchColor.G, findColor.G - gTol, findColor.G + gTol) ||
!TestRange(searchColor.B, findColor.B - bTol, findColor.B + bTol)) {
mismatches++;
if (mismatches > allowedMismatches) {
mismatches = 0;
goto notFound;
}
}
}
}
points.Add(new Point(j, i));
continue;
notFound:
;
}
}
}
}
Console.WriteLine(stopwatch.ElapsedMilliseconds);
return points;
}
Searching a moderately sized image (1000x1000) takes over 20 seconds. Removing the percent match takes it down to a few hundred milliseconds, so I think I've established where the major bottleneck is.
How can I make this run faster? Perhaps I could flatten the two-dimensional arrays down to one-dimensional arrays and then apply some sort of sequence check on the two to possibly match up the longest sequence of where the toFind bitmap data appears with the respective tolerances and match percent. If this would be a good solution, how would I begin to implement it?

c# combining two images, that contain parts of each other

I have 2 pictures, containing part of each other:
now I want to combine them together, but not repeating the common part, to have something like that:
What is the best way to do it?
#edit: That images are only examples of what I want to do with any two images, that contain part of each other, and that part is at the bottom of the first image, and at the top of the second.
here's a solution for your question :
I defined a function which takes 2 Bitmaps and returns the Combined Bitmap
, in this function , I store first 2 rows of the second bitmap in an array of byte so I can compare them with the first bitmap in the next step , then I start looking for the matched rows in the first bitmap whenever I fined the matched row in that , I store the y position
, now I combine those bitmaps according to the y I've already found !
Here's the Demo Project : Download
Here's the Solution File : Download
here's the results for :
Example 1
Example 2
and here's the function :
private Bitmap CombineImages(Bitmap bmp_1, Bitmap bmp_2)
{
if (bmp_1.Width == bmp_2.Width)
{
int bmp_1_Height, bmpWidth, bmp_2_Height;
bmpWidth = bmp_1.Width;
bmp_1_Height = bmp_1.Height;
bmp_2_Height = bmp_2.Height;
Color c;
bool notFound = false;
int firstMatchedRow = 0;
byte[,] bmp2_first2rows = new byte[3 * bmpWidth, 2];
for (int b = 0; b < 2; b++)
{
for (int a = 0; a < bmpWidth; a++)
{
c = bmp_2.GetPixel(a, b);
bmp2_first2rows[a * 3, b] = c.R;
bmp2_first2rows[a * 3 + 1, b] = c.G;
bmp2_first2rows[a * 3 + 2, b] = c.B;
}
}
for (int y = 0; y < bmp_1_Height - 1; y++)
{
for (int j = 0; j < 2; j++)
{
for (int x = 0; x < bmpWidth; x++)
{
c = bmp_1.GetPixel(x, y + j);
if ((bmp2_first2rows[x * 3, j] == c.R) &&
(bmp2_first2rows[x * 3 + 1, j] == c.G) &&
(bmp2_first2rows[x * 3 + 2, j] == c.B))
{
}
else
{
notFound = true;
break;
}
}
if (notFound)
{
break;
}
}
if (!notFound)
{
firstMatchedRow = y;
break;
}
else
{
notFound = false;
}
}
if (firstMatchedRow > 0)
{
Bitmap bmp = new Bitmap(bmpWidth, firstMatchedRow + bmp_2_Height);
Graphics g = Graphics.FromImage(bmp);
Rectangle RectDst = new Rectangle(0, 0, bmpWidth, firstMatchedRow);
Rectangle RectSrc;
g.DrawImage(bmp_1, RectDst, RectDst, GraphicsUnit.Pixel);
RectDst = new Rectangle(0, firstMatchedRow, bmpWidth, bmp_2_Height);
RectSrc = new Rectangle(0, 0, bmpWidth, bmp_2_Height);
g.DrawImage(bmp_2, RectDst, RectSrc, GraphicsUnit.Pixel);
return bmp;
}
else
{
return null;
}
}
else
{
return null;
}
}
And Finally I should mention that , these Fantastic Tutorials have Helped me a lot in Image Processing :
Image Processing for Dummies with C# and GDI+
Image Processing using C#
Hope it Helps :)

Rotating matrices

Objectives
Imagine that, we have matrix like
a11 a12 a13
a21 a22 a23
a31 a32 a33
What I want to do is, from textbox value rotate this matrix so that, for example if I write 2 and press rotate, program must keep both diagonal values of matrix (in this case a11, a22, a33, a13, a31) and rotate 2 times clockwise other values. So result must be like
a11 a32 a13
a23 a22 a21
a31 a12 a33
It must work for all N x N size matrices, and as you see every 4 rotation takes matrix into default state.
What I've done
So idea is like that, I have 2 forms. First takes size of matrix (1 value, for example if it's 5, it generates 5x5 matrix). When I press OK it generates second forms textbox matrix like that
Form 1 code
private void button1_Click(object sender, EventArgs e)
{
int matrixSize;
matrixSize = int.Parse(textBox1.Text);
Form2 form2 = new Form2(matrixSize);
form2.Width = matrixSize * 50 + 100;
form2.Height = matrixSize *60 + 200;
form2.Show();
//this.Hide();
}
Form 2 code generates textbox matrix from given value and puts random values into this fields
public Form2(int matrSize)
{
int counter = 0;
InitializeComponent();
TextBox[] MatrixNodes = new TextBox[matrSize*matrSize];
Random r = new Random();
for (int i = 1; i <= matrSize; i++)
{
for (int j = 1; j <= matrSize; j++)
{
var tb = new TextBox();
int num = r.Next(1, 1000);
MatrixNodes[counter] = tb;
tb.Name = string.Format("Node_{0}{1}", i, j);
Debug.Write(string.Format("Node_{0}{1}", i, j));
tb.Text = num.ToString();
tb.Location = new Point(j * 50, i * 50);
tb.Width = 30;
tb.Visible = true;
this.splitContainer1.Panel2.Controls.Add(tb);
counter++;
}
}
}
Form 2 has 1 textbox for controlling rotation (others are generated on the fly, programmatically). What I want to do is, when I enter rotation count and press Enter on this textbox, I want to rotate textbox matrix as I explained above. Can't figure out how to do it.
Copy both diagonals to separate arrays, then rotate your matrix and replace diagonals. Below code shows each step:
class Program
{
static void Main(string[] args)
{
int matrixSize = 3;
string[,] matrix = new string[matrixSize,matrixSize];
//create square matrix
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
matrix[x, y] = "a" + (x + 1).ToString() + (y + 1).ToString();
}
}
Console.WriteLine(Environment.NewLine + "Base square matrix");
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
Console.Write(matrix[x, y] + " ");
}
Console.Write(Environment.NewLine);
}
Console.ReadKey();
//copy diagonals
string[] leftDiagonal = new string[matrixSize];
string[] rightDiagonal = new string[matrixSize];
for (int x = 0; x < matrixSize; x++)
{
leftDiagonal[x] = matrix[x, x];
rightDiagonal[x] = matrix[matrixSize - 1 - x, x];
}
Console.WriteLine(Environment.NewLine + "Diagonals");
for (int x = 0; x < matrixSize; ++x)
{
Console.Write(leftDiagonal[x] + " " + rightDiagonal[x] + Environment.NewLine);
}
Console.ReadKey();
//rotate matrix
string[,] rotatedMatrix = new string[matrixSize, matrixSize];
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
rotatedMatrix[x, y] = matrix[matrixSize - y - 1, x];
}
}
Console.WriteLine(Environment.NewLine + "Rotated");
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
Console.Write(rotatedMatrix[x, y] + " ");
}
Console.Write(Environment.NewLine);
}
Console.ReadKey();
//rotate matrix again
string[,] rotatedMatrixAgain = new string[matrixSize, matrixSize];
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
rotatedMatrixAgain[x, y] = rotatedMatrix[matrixSize - y - 1, x];
}
}
Console.WriteLine(Environment.NewLine + "Rotated again");
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
Console.Write(rotatedMatrixAgain[x, y] + " ");
}
Console.Write(Environment.NewLine);
}
Console.ReadKey();
//replace diagonals
for (int x = 0; x < matrixSize; x++)
{
rotatedMatrixAgain[x, x] = leftDiagonal[x];
rotatedMatrixAgain[matrixSize - 1 - x, x] = rightDiagonal[x];
}
Console.WriteLine(Environment.NewLine + "Completed" + Environment.NewLine);
for (int x = 0; x < matrixSize; x++)
{
for (int y = 0; y < matrixSize; y++)
{
Console.Write(rotatedMatrixAgain[x, y] + " ");
}
Console.Write(Environment.NewLine);
}
Console.ReadKey();
}
}
I don't know C#, so I can only give a suggestion in pseudocode:
Input: An N by N matrix in
Output: The input matrix rotated as described in the OP out
for i = 1 to N
for j = 1 to N
if N - j != i and i != j // Do not change values on either diagonal
out[j][N-i] = in[i][j]
else
out[i][j] = in[i][j]
Disclaimer: This algorithm is untested. I suggest you use a debugger to check that it works as you want.
This seems like quite an unorthodox UI presentation, but you're not too far off in terms of being able to achieve your functionality. Instead of a linear array, a rectangular array will make your job much easier. The actual rotation could be implemented with a for loop repeating a single rotation (which would be implemented as in the case 1 code), but I've decided to combine them into the four possible cases. This actually allows you to enter a negative number for number of rotations. Which reminds me, you really should do more error checking. At least protect against int.Parse throwing an exception both places it's used (with a try catch block or by switching to int.TryParse) and make sure it returns a meaningful number (greater than 0, possibly set a reasonable maximum other than int.MaxValue) for matrixSize in button1_Click.
namespace RotatingMatrices
{
public class Form2 : Form
{
// note these class fields
private TextBox[,] matrixNodes;
private int matrixSize;
public Form2(int matrSize)
{
InitializeComponent();
// note these inits
matrixSize = matrSize;
matrixNodes = new TextBox[matrixSize, matrixSize];
Random r = new Random();
// note the new loop limits
for (int i = 0; i < matrixSize; i++)
{
for (int j = 0; j < matrixSize; j++)
{
var tb = new TextBox();
int num = r.Next(1, 1000);
// note the change in indexing
matrixNodes[i,j] = tb;
tb.Name = string.Format("Node_{0}_{1}", i, j);
Debug.Write(string.Format("Node_{0}_{1}", i, j));
tb.Text = num.ToString();
tb.Location = new Point(j * 50, i * 50);
tb.Width = 30;
tb.Visible = true;
this.splitContainer1.Panel2.Controls.Add(tb);
}
}
}
private void buttonRotate_Click(object sender, EventArgs e)
{
string[,] matrix = new string[matrixSize, matrixSize];
int rotations = (4 + int.Parse(textBoxRotations.Text)) % 4; // note the addition of and mod by 4
switch(rotations)
{
case 1: // rotate clockwise
for (int i = 0; i < matrixSize; i++)
{
for (int j = 0; j < matrixSize; j++)
{
matrix[j, matrixSize - i - 1] = matrixNodes[i, j].Text;
}
}
break;
case 2: // rotate 180 degrees
for (int i = 0; i < matrixSize; i++)
{
for (int j = 0; j < matrixSize; j++)
{
matrix[i, j] = matrixNodes[matrixSize - i - 1, matrixSize - j - 1].Text;
}
}
break;
case 3: // rotate counter-clockwise
for (int i = 0; i < matrixSize; i++)
{
for (int j = 0; j < matrixSize; j++)
{
matrix[i, j] = matrixNodes[j, matrixSize - i - 1].Text;
}
}
break;
default: // do nothing
return;
}
// restore diagonals
for(int i = 0; i < matrixSize; i++)
{
matrix[i, i] = matrixNodes[i, i].Text;
matrix[i, matrixSize - i - 1] = matrixNodes[i, matrixSize - i - 1].Text;
}
// write strings back to text boxes
for (int i = 0; i < matrixSize; i++)
{
for (int j = 0; j < matrixSize; j++)
{
matrixNodes[i, j].Text = matrix[i, j];
}
}
}
}
}
I decided to tackle the issue using a listView instead of a text box, which makes the logic easier for me. Using this method, I was able to think of the matrix as successive boxes. I start on the outside and move in toward the middle, changing the size of my box each time.
Also, rather than using two forms, I use one. At the top I have a textbox where the user enters the size they want the array to be, and a button labeled "Fill" (button2). And at the bottom I have a textbox where the user enters the degree of rotation. When they click "Rotate," it kicks off a process of adding values to linked lists, combining and shifting the list, and then writing back out to the matrix. I'm sure I made it more convoluted than it has to be, but it was a great learning exercise.
After looking over jerry's code above, I think I'm going to look into rectangular arrays. :)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Recycle
{
public partial class Form1 : Form
{
public int size;
public LinkedList<string> topRight = new LinkedList<string>();
public LinkedList<string> bottomLeft = new LinkedList<string>();
public LinkedList<string> myMatrix = new LinkedList<string>();
public LinkedList<string> shiftMatrix = new LinkedList<string>();
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
listView1.Clear();
size = int.Parse(textBox2.Text);
int c = 0;
int q = 0;
int w = 0;
string[] content = new string[size];
Random rnd = new Random();
for (c = 0; c < size; c++)
{
listView1.Columns.Add("", 25);
}
for (q = 0; q < size; q++)
{
for (w = 0; w < size; w++)
{
content[w] = rnd.Next(9,100).ToString();
}
ListViewItem lvi = new ListViewItem(content);
listView1.Items.Add(lvi);
}
}
public bool iseven(int size)
{
if (size % 2 == 0)
{
return true;
}
else
{
return false;
}
}
public void button1_Click(object sender, EventArgs e)
{
if (listView1.Items.Count < 3)
{
MessageBox.Show("Matrix cannot be rotated.");
return;
}
bool even = false;
int shift = int.Parse(textBox1.Text); //amount to shift by
int box = listView1.Items.Count - 1; //size of box
int half = Convert.ToInt32(listView1.Items.Count / 2);
int corner = 0; //inside corner of box
if (shift > listView1.Items.Count)
{
shift = shift % ((listView1.Items.Count - 2) * 4);
}
do
{
eachPass(shift, box, corner);
++corner;
--box;
} while (box >= half + 1);
}
public void eachPass(int shift, int box, int corner)
{
int x;
int i;
//Read each non-diagonal value into one of two lists
for (x = corner + 1; x < box; x++)
{
topRight.AddLast(listView1.Items[corner].SubItems[x].Text);
}
x = box;
for (i = corner + 1; i < box; i++)
{
topRight.AddLast(listView1.Items[i].SubItems[x].Text);
}
for (x = box - 1; x > corner; x--)
{
bottomLeft.AddLast(listView1.Items[box].SubItems[x].Text);
}
x = corner;
for (i = box - 1; i > corner; i--)
{
bottomLeft.AddLast(listView1.Items[i].SubItems[x].Text);
}
string myTest = "";
//join the two lists, so they can be shifted
foreach (string tR in topRight)
{
myMatrix.AddLast(tR);
}
foreach (string bL in bottomLeft)
{
myMatrix.AddLast(bL);
}
int sh;
//shift the list using another list
for (sh = shift; sh < myMatrix.Count; sh++)
{
shiftMatrix.AddLast(myMatrix.ElementAt(sh));
}
for (sh = 0; sh < shift; sh++)
{
shiftMatrix.AddLast(myMatrix.ElementAt(sh));
}
//we need the sizes of the current lists
int trCnt = topRight.Count;
int blCnt = bottomLeft.Count;
//clear them for reuse
topRight.Clear();
bottomLeft.Clear();
int s;
//put the shifted values back
for (s = 0; s < trCnt; s++)
{
topRight.AddLast(shiftMatrix.ElementAt(s));
}
for (s = blCnt; s < shiftMatrix.Count; s++)
{
bottomLeft.AddLast(shiftMatrix.ElementAt(s));
}
int tRn = 0;
int bLn = 0;
//write each non-diagonal value from one of two lists
for (x = corner + 1; x < box; x++)
{
listView1.Items[corner].SubItems[x].Text = topRight.ElementAt(tRn);
++tRn;
}
x = box;
for (i = corner + 1; i < box; i++)
{
listView1.Items[i].SubItems[x].Text = topRight.ElementAt(tRn);
++tRn;
}
for (x = box - 1; x > corner; x--)
{
listView1.Items[box].SubItems[x].Text = bottomLeft.ElementAt(bLn);
++bLn;
}
x = corner;
for (i = box - 1; i > corner; i--)
{
listView1.Items[i].SubItems[x].Text = bottomLeft.ElementAt(bLn);
++bLn;
}
myMatrix.Clear();
shiftMatrix.Clear();
topRight.Clear();
bottomLeft.Clear();
}
}
}

Categories