Related
I've created a program for a project that tests images against one another to see whether or not it's the same image or not. I've decided to use correlation since the images I am using are styled in the same way and with this, I've been able to get everything working up to this point.
I now wish to create an array of images again, but this time, in order of their correlation. So for example, if I'm testing a 50 pence coin and I test 50 images against the 50 pence coin, I want the highest 5 correlations to be stored into an array, which can then be used for later use. But I'm unsure how to do this as each item in the array will need to have more than one variable, which will be the image location/name of the image and it's correlation percentage.
%Program Created By Ben Parry, 2016.
clc(); %Simply clears the console window
%Targets the image the user picks
inputImage = imgetfile();
%Targets all the images inside this directory
referenceFolder = 'M:\Project\MatLab\Coin Image Processing\Saved_Images';
if ~isdir(referenceFolder)
errorMessage = print('Error: Folder does not exist!');
uiwait(warndlg(errorMessage)); %Displays an error if the folder doesn't exist
return;
end
filePattern = fullfile(referenceFolder, '*.jpg');
jpgFiles = dir(filePattern);
for i = 1:length(jpgFiles)
baseFileName = jpgFiles(i).name;
fullFileName = fullfile(referenceFolder, baseFileName);
fprintf(1, 'Reading %s\n', fullFileName);
imageArray = imread(fullFileName);
imshow(imageArray);
firstImage = imread(inputImage); %Reading the image
%Converting the images to Black & White
firstImageBW = im2bw(firstImage);
secondImageBW = im2bw(imageArray);
%Finding the correlation, then coverting it into a percentage
c = corr2(firstImageBW, secondImageBW);
corrValue = sprintf('%.0f%%',100*c);
%Custom messaging for the possible outcomes
corrMatch = sprintf('The images are the same (%s)',corrValue);
corrUnMatch = sprintf('The images are not the same (%s)',corrValue);
%Looping for the possible two outcomes
if c >=0.99 %Define a percentage for the correlation to reach
disp(' ');
disp('Images Tested:');
disp(inputImage);
disp(fullFileName);
disp (corrMatch);
disp(' ');
else
disp(' ');
disp('Images Tested:');
disp(inputImage);
disp(fullFileName);
disp(corrUnMatch);
disp(' ' );
end;
imageArray = imread(fullFileName);
imshow(imageArray);
end
You can use struct() function to create structures.
Initializing an array of struct:
imStruct = struct('fileName', '', 'image', [], 'correlation', 0);
imData = repmat(imStruct, length(jpgFiles), 1);
Setting field values:
for i = 1:length(jpgFiles)
% ...
imData(i).fileName = fullFileName;
imData(i).image = imageArray;
imData(i).correlation = corrValue;
end
Extract values of correlation field and select 5 highest correlations:
corrList = [imData.correlation];
[~, sortedInd] = sort(corrList, 'descend');
selectedData = imData(sortedInd(1:5));
I have a list of xy points that I'm trying to sum together and identify the centroid, but it only uses the last value in the row. I'm trying to create a centroid for each state, Here's the code:
Total_X1 = 0
Total_Y1 = 0
TotalPop1 = 0
#Cat = "cali"
cntyName1 = "cnty"
stateName1 = "statename"
for row in cursor:
#if row[0] >= : ### for condition that is met
#if row[0]== []:
TheStateName1 = row[0]
thecntyName1 = row[4]
idpoly1 = row[5]
idobject1 = row[6]
stateFIPS1 = row[7]
countyFIPS1 = row[8]
fips1 = row[9]
fipSnum1 = row[10]
fipsNumer1 = row[11]
#totarea = row[12]
XPoint = row [13]
YPoint = row[14]
#print Cat
print TheStateName1
print thecntyName1
print row ### do something with that value!
Total_X1 += row[2] *row[3]
print Total_X1
Total_Y1 += row[1] *row[3]
print Total_Y1
TotalPop1 += row[3]
print TotalPop1
print ""
print "X is: " , Total_X1
print "POP is: " , TotalPop1
centroid_X1 = Total_X1/TotalPop1
print "your x centroid is: ",centroid_X1
print ""
#print Cat
print thecntyName1
print TheStateName1
Any Suggestions, Thanks!
The cursor can only 'see' one row at a time, you have to pull info from that row and store it elsewhere.
loc_list = [(row[0], row[1]) for row in arcpy.da.SearchCursor(dataset, ['X_coord', 'Y_coord'])
Will give you a list of X,Y tuples from your attribute table.
After that you've got multiple options for turning that list of tuples into a spatial dataset before calculating the mean - start by reading the ESRI documentation for arcpy.Point and all the related topics linked, and go from there. If you have 10.3 or above you can use Mean Center once you have a point layer.
You'll probably get a wrong answer if you just take the mean of the X and Y without projecting first, so don't.
I have the below code I'm trying to put together and I'm running into a Run-time error '9' subscript out of range. This does work through the first run through then errors. I don't see why it won't allow for the string to go forward. From what I'm reading it should go through the application changing the X values with Y value 1 and when completed with that set to go to the next Y and start the whole process again until the end of Y. Any help would be appreciated.
Dim Cat(1 To 10) As String
Cat(1) = "010" 'SD
Cat(2) = "020" 'FD
Cat(3) = "050" 'WVID
Cat(4) = "040" 'VID
Cat(5) = "030" 'MEM
Cat(6) = "080" 'ACC
Cat(7) = "060" 'HDMI
Cat(8) = "070" 'SSD
Cat(9) = "090" 'POWER
Cat(10) = "990" 'ZRM
Dim Month(1 To 12) As String
Month(1) = "January"
Month(2) = "February"
Month(3) = "March"
Month(4) = "April"
Month(5) = "May"
Month(6) = "June"
Month(7) = "July"
Month(8) = "August"
Month(9) = "September"
Month(10) = "October"
Month(11) = "November"
Month(12) = "December"
For Y = 1 To UBound(Cat)
For X = 1 To UBound(Month)
Month(X) = Application.WorksheetFunction.SumIf(Sheets(Month(X)).Columns("AO"), Cat(Y), Sheets(Month(X)).Columns("AG"))
Next X
Cells(3 + Y, 41).Value = Application.WorksheetFunction.Sum(Month(1), Month(2), Month(3), Month(4), Month(5), Month(6), Month(7), Month(8), Month(9), Month(10), Month(11), Month(12))
Next Y
End Sub
On the first run through the loop indexed by X you are computing a conditional sum of data stored in Sheet "January". And then overwriting "January" with that value in Month(X). Let's say that that value is 42. On your next run through the loop 42 is in Month(X) so you are looking for Sheets(42), which probably isn't a valid worksheet. I would try this instead.
dim temp as double
For Y = 1 To UBound(Cat)
temp = 0# '0 as a double.
For X = 1 To UBound(Month)
temp = temp + Application.WorksheetFunction.SumIf(Sheets(Month(X)).Columns("AO"), Cat(Y), Sheets(Month(X)).Columns("AG"))
Next X
Cells(3 + Y, 41).Value = temp
Next Y
This way we don't need to store all of the sums from each sheet, since we only use them to add them all together.
We are using the Interop PowerPoint Chart type to generate an area chart as shown in the figure. We need the "broken" y-Axis. We dont want the break on the bars itself - we need the break only on the y-Axis. But are unable to find a property or a method to achieve this.
This a winforms application. Would really appreciate some pointers...
Accidentally stumbled upon this question, and I let my curiosity takes over.
I got how it's done taken from this site.
I'm using example data from above site for this walkthrough.
The step roughly like this:
Assign cut value for data separation. Separate data using a cut value (I use cut value 7,500,000 for the example)
This is data separation from the example (above is the original, below is the separated):
May June July
London 1,234,565 1,452,369 1,478,852
Paris 2,363,645 34,568,876 5,562,413
Madrid 32,645,254 3,211,654 5,857,421
Brussels 5,914,753 5,544,221 3,620,015
Lisbon 5,824,676 4,541,258 4,015,876
Munich 2,501,478 6,325,698 4,569,872
May June July Column4 Column5 Column6
London 1,234,565 1,452,369 1,478,852 0 0 0
Paris 2,363,645 7,500,000 5,562,413 0 34,568,876 0
Madrid 7,500,000 3,211,654 5,857,421 32,645,254 0 0
Brussels 5,914,753 5,544,221 3,620,015 0 0 0
Lisbon 5,824,676 4,541,258 4,015,876 0 0 0
Munich 2,501,478 6,325,698 4,569,872 0 0 0
Assign Column4, Column5, and Column6 into secondary axis.
Dim c As Microsoft.Office.Interop.PowerPoint.Chart
Dim sc As Microsoft.Office.Interop.PowerPoint.SeriesCollection = Nothing
Dim sr As Microsoft.Office.Interop.PowerPoint.Series = Nothing
sc = c.SeriesCollection
For i = 4 To sc.Count
sr = sc.SeriesCollection(i)
sr.AxisGroup = Microsoft.Office.Interop.PowerPoint.XlAxisGroup.xlSecondary
Next
Change Primary and Secondary Axis scale to fit as though the chart was separated. I change the primary axis scale from 0 to 1.6e7, and secondary axis scale from -7.0e7 to 7.0e7. At the same time, change display unit in millions, and remove all gridlines.
Dim ax As Microsoft.Office.Interop.PowerPoint.Axes
Dim axpri As Microsoft.Office.Interop.PowerPoint.Axis
Dim axsec As Microsoft.Office.Interop.PowerPoint.Axis
ax = c.Axes
axpri = ax.Item(Microsoft.Office.Interop.PowerPoint.XlAxisType.xlValue, _
Microsoft.Office.Interop.PowerPoint.XlAxisGroup.xlPrimary)
axsec = ax.Item(Microsoft.Office.Interop.PowerPoint.XlAxisType.xlValue, _
Microsoft.Office.Interop.PowerPoint.XlAxisGroup.xlSecondary)
axpri.MinimumScale = 0
axpri.MaximumScale = 1.6e7
axpri.DisplayUnit = Microsoft.Office.Interop.PowerPoint.XlDisplayUnit.xlMillions
axpri.HasMajorGridlines = False
axpri.HasMinorGridlines = False
axsec.MinimumScale = -7.0e7
axsec.MaximumScale = 7.0e7
axsec.DisplayUnit = Microsoft.Office.Interop.PowerPoint.XlDisplayUnit.xlMillions
axsec.HasMajorGridlines = False
axsec.HasMinorGridlines = False
Change Primary and Secondary Axis number format so that each axis only show its own intended value. Primary Axis more than 8M will not be shown, and Secondary Axis less than 30M will not be shown.
axpri.TickLabels.NumberFormat = "[<=8]0;;;"
axsec.TickLabels.NumberFormat = "[>=30]0;;;"
Recolor series in Secondary Axis to match series in Primary Axis.
Dim srPrev As Microsoft.Office.Interop.PowerPoint.Series = Nothing
For i = 4 To sc.Count
sr = sc.SeriesCollection(i)
srPrev = sc.SeriesCollection(i - 3)
sr.Format.Fill.ForeColor.RGB = srPrev.Format.Fill.ForeColor.RGB
Next
Delete Legend for Column4, Column5, and Column6 for a seamless Chart Legend.
c.Legend.LegendEntries(4).Delete()
c.Legend.LegendEntries(5).Delete()
c.Legend.LegendEntries(6).Delete()
[Optional] Add a neat color gradient for Data Points that exceed cut values.
Dim p As Microsoft.Office.Interop.PowerPoint.Point = Nothing
p = c.SeriesCollection("June").Points("Paris")
p.Format.Fill.TwoColorGradient(Microsoft.Office.Core.MsoGradientStyle.msoGradientHorizontal, 1)
p.Format.Fill.GradientAngle = 270
p.Format.Fill.GradientStops.Insert(p.Format.Fill.ForeColor.RGB, 0.8)
p.Format.Fill.GradientStops.Insert(p.Format.Fill.BackColor.RGB, 0.97)
p = c.SeriesCollection("May").Points("Madrid")
p.Format.Fill.TwoColorGradient(Microsoft.Office.Core.MsoGradientStyle.msoGradientHorizontal, 1)
p.Format.Fill.GradientAngle = 270
p.Format.Fill.GradientStops.Insert(p.Format.Fill.ForeColor.RGB, 0.8)
p.Format.Fill.GradientStops.Insert(p.Format.Fill.BackColor.RGB, 0.97)
p = c.SeriesCollection("Column5").Points("Paris")
p.Format.Fill.TwoColorGradient(Microsoft.Office.Core.MsoGradientStyle.msoGradientHorizontal, 1)
p.Format.Fill.GradientAngle = 90
p.Format.Fill.GradientStops.Insert(p.Format.Fill.ForeColor.RGB, 0.7)
p.Format.Fill.GradientStops.Insert(p.Format.Fill.BackColor.RGB, 0.95)
p = c.SeriesCollection("Column4").Points("Madrid")
p.Format.Fill.TwoColorGradient(Microsoft.Office.Core.MsoGradientStyle.msoGradientHorizontal, 1)
p.Format.Fill.GradientAngle = 90
p.Format.Fill.GradientStops.Insert(p.Format.Fill.ForeColor.RGB, 0.7)
p.Format.Fill.GradientStops.Insert(p.Format.Fill.BackColor.RGB, 0.95)
Voila! Hard work pays off, a broken y axis in PowerPoint chart.
I wrote a script that returns several text boxes in a figure. The text boxes are moveable (I can drag and drop them), and their positions are predetermined by the data in an input matrix (the data from the input matrix is applied to the respective positions of the boxes by nested for loop). I want to create a matrix which is initially a copy of the input matrix, but is UPDATED as I change the positions of the boxes by dragging them around. How would I update their positions? Here's the entire script
function drag_drop=drag_drop(tsinput,infoinput)
[x,~]=size(tsinput);
dragging = [];
orPos = [];
fig = figure('Name','Docker Tool','WindowButtonUpFcn',#dropObject,...
'units','centimeters','WindowButtonMotionFcn',#moveObject,...
'OuterPosition',[0 0 25 30]);
% Setting variables to zero for the loop
plat_qty=0;
time_qty=0;
k=0;
a=0;
% Start loop
z=1:2
for idx=1:x
if tsinput(idx,4)==1
color='red';
else
color='blue';
end
a=tsinput(idx,z);
b=a/100;
c=floor(b); % hours
d=c*100;
e=a-d; % minutes
time=c*60+e; % time quantity to be used in 'position'
time_qty=time/15;
plat_qty=tsinput(idx,3)*2;
box=annotation('textbox','units','centimeters','position',...
[time_qty plat_qty 1.5 1.5],'String',infoinput(idx,z),...
'ButtonDownFcn',#dragObject,'BackgroundColor',color);
% need to new=get(box,'Position'), fill out matrix OUT of loop
end
fillmenu=uicontextmenu;
hcb1 = 'set(gco, ''BackgroundColor'', ''red'')';
hcb2 = 'set(gco, ''BackgroundColor'', ''blue'')';
item1 = uimenu(fillmenu, 'Label', 'Train Full', 'Callback', hcb1);
item2 = uimenu(fillmenu, 'Label', 'Train Empty', 'Callback', hcb2);
hbox=findall(fig,'Type','hggroup');
for jdx=1:x
set(hbox(jdx),'uicontextmenu',fillmenu);
end
end
new_arr=tsinput;
function dragObject(hObject,eventdata)
dragging = hObject;
orPos = get(gcf,'CurrentPoint');
end
function dropObject(hObject,eventdata,box)
if ~isempty(dragging)
newPos = get(gcf,'CurrentPoint');
posDiff = newPos - orPos;
set(dragging,'Position',get(dragging,'Position') + ...
[posDiff(1:2) 0 0]);
dragging = [];
end
end
function moveObject(hObject,eventdata)
if ~isempty(dragging)
newPos = get(gcf,'CurrentPoint');
posDiff = newPos - orPos;
orPos = newPos;
set(dragging,'Position',get(dragging,'Position') + [posDiff(1:2) 0 0]);
end
end
end
% Testing purpose input matrices:
% tsinput=[0345 0405 1 1 ; 0230 0300 2 0; 0540 0635 3 1; 0745 0800 4 1]
% infoinput={'AJ35 NOT' 'KL21 MAN' 'XPRES'; 'ZW31 MAN' 'KM37 NEW' 'VISTA';
% 'BC38 BIR' 'QU54 LON' 'XPRES'; 'XZ89 LEC' 'DE34 MSF' 'DERP'}
If I understand you correctly (and please post some code if I'm not), then all you need is indeed a set/get combination.
If boxHandle is a handle to the text-box object, then you get its current position by:
pos = get (boxHandle, 'position')
where pos is the output array of [x, y, width, height].
In order to set to a new position, you use:
set (boxHandle, 'position', newPos)
where newPos is the array of desired position (with the same structure as pos).
EDIT
Regarding to updating your matrix, since you have the handle of the object you move, you actually DO have access to the specific text box.
When you create each text box, set a property called 'UserData' with the associated indices of tsinput used for that box. In your nested for loop add this
set (box, 'UserData', [idx, z]);
after the box is created, and in your moveObject callback get the data by
udata = get(dragging,'UserData');
Then udata contains the indices of the elements you want to update.