-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First Working Draft of Integration Code
- Loading branch information
Christian
committed
Apr 28, 2020
1 parent
e3adf81
commit dcdf0a0
Showing
13 changed files
with
576 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
%% Run the Toolbox Dependency Analysis | ||
fileList = {}; | ||
|
||
moduleFilesStruct = dir('Modules'); | ||
moduleFiles = arrayfun(@(x) [x.folder '\' x.name],moduleFilesStruct,'UniformOutput',false); | ||
|
||
mainFilesStruct = dir; | ||
mainFiles = arrayfun(@(x) x.name, mainFilesStruct, 'UniformOutput',false); | ||
|
||
for i = 1:length(moduleFiles) | ||
if(endsWith(moduleFiles{i} ,'.m')); fileList{end+1} = moduleFiles{i}; end; | ||
end | ||
|
||
for i = 1:length(mainFiles) | ||
if(endsWith(mainFiles{i} ,'.m')); fileList{end+1} = mainFiles{i}; end; | ||
end | ||
|
||
toolBoxDependencies = dependencies.toolboxDependencyAnalysis(fileList); | ||
dependencies.toolboxDependencyAnalysis({'RESClassifier.m'}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,326 @@ | ||
% ========================================================================= | ||
% === Calibration Package for Automated Surface Inspection Integration === | ||
% ========================================================================= | ||
% Author: Christian Schirmer (christian.schirmer@uconn.edu) | ||
% ========================================================================= | ||
|
||
classdef Calibration < handle | ||
|
||
properties | ||
% calData stores region bitmasks, along with corresponding pose and | ||
% section identifiers | ||
calData = table( ... | ||
'Size',[0 3],... | ||
'VariableTypes',{'double', 'double', 'cell'},... | ||
'VariableNames',{'PoseID','SectionID','Bitmask'}) | ||
|
||
% calImages stores calibration images. They are stored as key-value | ||
% pairs <Key, Value> --> <PoseID, Image> | ||
calImages = containers.Map('KeyType','double','ValueType','any'); | ||
end | ||
|
||
% User-Accessible Calibration Functions | ||
methods (Access = public) | ||
function this = Calibration(varargin) | ||
% CALIBRATION Calibration object constructor. Data will be loaded | ||
% from filename argument, if specified. | ||
if(nargin == 0) | ||
% No input argument: Do nothing, proceed normally. | ||
elseif(nargin ==1) | ||
% 1 input argument: Filename. Load data from this file. | ||
this.loadData(varargin{1}); | ||
end | ||
end | ||
|
||
function addPose(this, PoseID, image_filepath) | ||
% ADDPOSE: Adds a pose using a calibration image. | ||
% A pose is added with the specified PoseID and calibration image | ||
% at image_filepath. The user is prompted to draw regions around | ||
% the different sections to create the pose-to-section mapping. | ||
|
||
% If the pose already exists in the data table, ask the user if | ||
% they would like to replace the pose | ||
|
||
% Check to see if the pose already exists in the table | ||
if(any(this.calData.PoseID == PoseID) | this.calImages.isKey(PoseID)) | ||
userInput = questdlg(... | ||
['Pose ' num2str(PoseID) ' has already been added. ' ... | ||
'All calibration data associated with this pose ' ... | ||
'will be erased. Would you like to continue?'], ... | ||
['Overwrite Pose' num2str(PoseID) '?'], ... | ||
'Yes','No','No'); | ||
switch userInput | ||
case 'Yes' | ||
this.removePose(PoseID); | ||
otherwise | ||
return; | ||
end | ||
end | ||
|
||
% Read the calibration image in from the specified filepath | ||
this.calImages(PoseID) = imread(image_filepath); | ||
|
||
% Now we go through the region-drawing procedure to create | ||
% bitmasks for all the sections in the calibration image. | ||
sectionsComplete = false; | ||
while(~sectionsComplete) | ||
try | ||
this.addRegion(PoseID); | ||
catch MExc | ||
if(strcmp(MExc.identifier,'Calibration:addRegion:drawROIWindowClosed')) | ||
% This error is thrown when the user closes the UI | ||
% for adding a region before actually drawing the | ||
% region. This indicates the user would like to | ||
% stop adding regions. | ||
sectionsComplete = true; | ||
elseif(strcmp(MExc.identifier,'Calibration:addRegion:sectionInputCancelled')) | ||
% User Cancelled SectionID input. Do nothing. | ||
% Section will not be saved. User will be | ||
% re-prompted to draw section. | ||
else | ||
% Any other errors are not expected and should be | ||
% re-thrown. | ||
rethrow(MExc); | ||
end | ||
end | ||
end | ||
end | ||
|
||
function removePose(this, PoseID) | ||
% REMOVEPOSE: Removes all data associated with the specified Pose. | ||
% This includes the calibration image, and all regions associated | ||
% with the pose. | ||
|
||
% Remove calibration image | ||
this.calImages.remove(PoseID); | ||
% Remove all regions associated with the specified pose | ||
this.calData = this.calData((this.calData.PoseID~=PoseID),:); | ||
end | ||
|
||
function addRegion(this, PoseID) | ||
% ADDREGION: Prompts the user to draw a region in the | ||
% calibration image for the given pose. Prompts user for section | ||
% number. Generates bitmap and appends to calibration data. | ||
|
||
% === Retrieve Existing Bitmasks for this PoseID === | ||
% Get all bitmasks associated with that PoseID | ||
bm_list = this.getBitmasks(PoseID); | ||
% Flatten all the bitmasks on top of each other for display, collect | ||
% information for labeling: section centroid, label text | ||
bm_centroids = {}; | ||
bm_labels = {}; | ||
for i = 1:height(bm_list) | ||
% Retrieve the i'th bitmask | ||
bitmask_i = logical(bm_list{i,'Bitmask'}{1}); | ||
if(i==1) | ||
% First bitmask will not need to be flattened. Assign it as | ||
% totalMask | ||
totalMask = bitmask_i; | ||
else | ||
% Flatten current bitmask into totalMask | ||
totalMask = logical(totalMask) | bitmask_i; | ||
end | ||
|
||
% Find Centroid of Region, Save SectionID as Label | ||
% Reference: https://www.mathworks.com/matlabcentral/answers/322369-find-centroid-of-binary-image | ||
[grid_y, grid_x] = ndgrid(1:size(totalMask,1),1:size(totalMask,2)); | ||
bm_centroids{i} = mean([grid_x(logical(bitmask_i)),grid_y(logical(bitmask_i))]); | ||
|
||
% Store SectionID as label | ||
bm_labels{i} = num2str(bm_list{i,'SectionID'}); | ||
end | ||
|
||
% === Draw the Figure for the User to Draw a Region on === | ||
|
||
% Have the user define a region by drawing a polygon | ||
roi = images.roi.Polygon; | ||
% Create a figure | ||
thisFig = figure; | ||
% Show the calibration image | ||
curCalImage = imshow(this.calImages(PoseID)); | ||
title('Please draw boundary around a section (or close window if complete)'); | ||
|
||
% If there are existing bitmasks, show them | ||
if(height(bm_list)>0) | ||
hold on; | ||
% Create a green mask layer to display over sections | ||
maskLayer = cat(3,zeros(size(totalMask)),ones(size(totalMask)),zeros(size(totalMask))); | ||
% Draw the already-defined bitmasks on top of the image | ||
maskIm = imshow(maskLayer); | ||
% Label the masks | ||
for i = 1:length(bm_centroids) | ||
text(bm_centroids{i}(1),bm_centroids{i}(2),bm_labels{i}); | ||
end | ||
hold off; | ||
|
||
% Set the mask layer transparency to 20% | ||
set(maskIm,'AlphaData',totalMask*.2); | ||
end | ||
|
||
|
||
% Add the ROI drawing tool to the figure so the user can draw | ||
% a region around the next subsection | ||
draw(roi); | ||
|
||
% Check to see if window closed | ||
if(~isvalid(roi)) | ||
throw(MException('Calibration:addRegion:drawROIWindowClosed','Draw ROI window closed before ROI was drawn')); | ||
end | ||
|
||
% Generate the Bitmask | ||
bitmask = createMask(roi, curCalImage); | ||
|
||
% Prompt the user for a section number | ||
userInput = inputdlg(... | ||
'SectionID associated with boundary:',... | ||
'Enter SectionID'); | ||
if(size(userInput)==[0 0]) % Check to see if user has cancelled input | ||
delete(thisFig); | ||
throw(MException('Calibration:addRegion:sectionInputCancelled','User cancelled section input')); | ||
end | ||
secID = str2num(userInput{1}); | ||
|
||
% Check to see if the section already exists in the calibration | ||
% data. User can Replace, Merge, or Cancel. | ||
if(any(... | ||
(this.calData.SectionID == secID) & ... | ||
(this.calData.PoseID == PoseID))... | ||
) | ||
userInput = questdlg(... | ||
['Pose ' num2str(PoseID) ' already has a region ' ... | ||
'defined for section ' num2str(secID) '. Would you' ... | ||
' like to replace the existing region, merge in ' ... | ||
' the new selection, or leave the existing region' ... | ||
' as-is?'], ... | ||
['Region Conflict: Pose' num2str(PoseID) ', Section'... | ||
num2str(secID)], ... | ||
'Replace','Merge','Cancel', 'Replace'); | ||
switch userInput | ||
case 'Replace' | ||
% Remove the existing bitmask entry for this section, | ||
% replace with the new one. | ||
this.removeCalData(PoseID, secID); | ||
this.appendCalData(PoseID, secID, bitmask); | ||
case 'Merge' | ||
% Merge the existing bitmask with the new one. | ||
old_bm = this.calData(this.calData.PoseID==PoseID & this.calData.SectionID==secID,:).Bitmask{1}; | ||
this.calData{this.calData.PoseID==PoseID & this.calData.SectionID==secID,'Bitmask'}= ... | ||
{(old_bm | bitmask)}; | ||
case 'Cancel' | ||
% Do nothing. | ||
otherwise | ||
% User input closed. Do nothing. | ||
end | ||
else | ||
% Save the data back to calData table | ||
this.appendCalData(PoseID, secID, bitmask); | ||
end | ||
|
||
% Close the figure | ||
delete(thisFig); | ||
end | ||
|
||
function save(this, filename) | ||
% SAVE: Saves a .mat file containing the full Calibration object | ||
builtin('save',filename, 'this'); | ||
end | ||
|
||
function bitmasks = getBitmasks(this, PoseID) | ||
% GETBITMASKS: Get a table of Bitmasks and SectionIDs for a given PoseID | ||
bitmasks = this.calData((this.calData.PoseID==PoseID),{'SectionID', 'Bitmask'}); | ||
end | ||
|
||
function viewPose(this, PoseID) | ||
% VIEWPOSE: Displays the calibration image for the specified pose, | ||
% as well as all regions that have been associated with the pose. | ||
figure; | ||
imshow(this.getPoseImage(PoseID)); | ||
title(['Current Calibration: Pose ' num2str(PoseID)]); | ||
|
||
end | ||
end | ||
|
||
% Private 'Helper' Functions | ||
methods (Access = private) | ||
function this = appendCalData(this, PoseID, SectionID, bitmask) | ||
% Appends a row to the calData table | ||
this.calData = [this.calData; {PoseID, SectionID, {bitmask}}]; | ||
end | ||
|
||
function removeCalData(this, PoseID, SectionID) | ||
% Remove a row from the calData table (row(s) corresponding to the | ||
% given PoseID and SectionID | ||
this.calData = this.calData(this.calData.PoseID~=PoseID | this.calData.SectionID ~= SectionID,:); | ||
end | ||
|
||
function loadData(this,filename) | ||
% Loads saved data from a .mat file into the Calibration object | ||
fileData = load(filename); | ||
this.calData = fileData.this.calData; | ||
this.calImages = fileData.this.calImages; | ||
end | ||
|
||
function compositeImage = getPoseImage(this, PoseID) | ||
|
||
% === Retrieve Existing Bitmasks for this PoseID === | ||
% Get all bitmasks associated with that PoseID | ||
bm_list = this.getBitmasks(PoseID); | ||
% Flatten all the bitmasks on top of each other for display, collect | ||
% information for labeling: section centroid, label text | ||
bm_centroids = {}; | ||
bm_labels = {}; | ||
for i = 1:height(bm_list) | ||
% Retrieve the i'th bitmask | ||
bitmask_i = logical(bm_list{i,'Bitmask'}{1}); | ||
if(i==1) | ||
% First bitmask will not need to be flattened. Assign it as | ||
% totalMask | ||
totalMask = bitmask_i; | ||
else | ||
% Flatten current bitmask into totalMask | ||
totalMask = logical(totalMask) | bitmask_i; | ||
end | ||
|
||
% Find Centroid of Region, Save SectionID as Label | ||
% Reference: https://www.mathworks.com/matlabcentral/answers/322369-find-centroid-of-binary-image | ||
[grid_y, grid_x] = ndgrid(1:size(totalMask,1),1:size(totalMask,2)); | ||
bm_centroids{i} = mean([grid_x(logical(bitmask_i)),grid_y(logical(bitmask_i))]); | ||
|
||
% Store SectionID as label | ||
bm_labels{i} = num2str(bm_list{i,'SectionID'}); | ||
end | ||
|
||
% Retrieve the calibration image associated with the pose | ||
calImage = this.calImages(PoseID); | ||
|
||
% Define the transparency of the bitmasks over the calibration | ||
% image | ||
alpha = .3; | ||
|
||
% Create a transparency map: alpha transparency within the | ||
% bitmap region, full transparency everywhere else. | ||
alpha_map = (alpha*totalMask); | ||
|
||
% Create a green-only layer | ||
green_image = 255*cat(3,zeros(size(totalMask)),ones(size(totalMask)),zeros(size(totalMask))); | ||
|
||
% Convert the bitmask to a green RGB image | ||
% bm_image = uint8(cat(3,zeros(size(totalMask)),totalMask*255,zeros(size(totalMask)))); | ||
|
||
% Paint the transparent bitmask over the calibration image | ||
% Reference: https://en.wikipedia.org/wiki/Alpha_compositing | ||
compositeImage = uint8((green_image).*alpha_map + double(calImage).*(1-alpha_map)); | ||
|
||
|
||
% Add the section labels to the image. | ||
compositeImage = insertText(compositeImage,... | ||
reshape(cell2mat(bm_centroids),2,length(bm_centroids))',... | ||
bm_labels,... | ||
'AnchorPoint', 'Center',... | ||
'FontSize',min(floor(size(compositeImage,2)/40),200)); | ||
|
||
end | ||
|
||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
function img = Func_Capture_Image() | ||
%FUNC_CAPTURE_IMAGE Implementation of image capture from the camera. | ||
% This function should return an n x m x 3 uint8 image array | ||
|
||
test = 1; | ||
|
||
if(~test) | ||
% Initialize a connection to the camera | ||
g = gigecam('169.254.90.219','PixelFormat', 'BayerBG8'); | ||
|
||
% Change the ExposureTime setting (in us) | ||
g.ExposureTimeAbs = 20000; | ||
|
||
% Acquire a single image from the camera | ||
img = snapshot(g); | ||
|
||
% Clean up by clearing the object. | ||
clear g; | ||
else | ||
% Just return a test image | ||
img = imread('./Data/testImage13.bmp'); | ||
end | ||
|
||
|
||
|
||
end | ||
|
Oops, something went wrong.