//手動でEmbeddable PythonへのPathを切り替え(存在の有無を調査)
AppDataDir:=ExtractFilePath(Application.ExeName)+'Python39-32';
//AppDataDir:=ExtractFilePath(Application.ExeName)+'Python39-64';
if DirectoryExists(AppDataDir) then
begin
end;
Traceback (most recent call last):
File "E:\採点プログラム\xxx.py", line 138, in <module>
model.load()
File "E:\採点プログラム\xxx.py", line 58, in load
self.interpreter = tflite.Interpreter(model_path=self.model_file)
File "E:\WPy64-3980\python-3.9.8.amd64\lib\site-packages\tensorflow\lite\python\interpreter.py", line 455, in __init__
_interpreter_wrapper.CreateWrapperFromFile(
ValueError: Could not open 'E:\採点プログラム\saved_model.tflite'.
[Finished in 5.174s]
implementation
uses
System.AnsiStrings;
//System.AnsiStringsは、起動Path中の全角文字の有無を調査するために追加
procedure TFormCollaboration.FormCreate(Sender: TObject);
var
i,j:integer;
・・・ 略 ・・・
//引数に指定した文字列が半角か全角かチェックする
function OnlySingleByte(const S: AnsiString): Boolean;
var
i: Integer;
begin
for i:=1 to Length(S) do
//System.SysUtilsのByteType関数(非推奨)が呼び出される
//if ByteType(S, i) <> mbSingleByte then
//usesにSystem.AnsiStringsが必要
if System.AnsiStrings.ByteType(S, i) <> mbSingleByte then
begin
Result := False;
Exit;
end;
Result := True;
end;
begin
//起動Path中の全角文字の有無を調査
//[dcc64 警告]データ損失の可能性がある文字列の暗黙のキャスト ('string' から
//'AnsiString')を表示しないようにAnsiString()で明示的に型キャストした
if not OnlySingleByte(AnsiString(Application.ExeName)) then
begin
MessageDlg('AC_Reader.exeへのPath中に全角文字が含まれていないか、'+
'確認してください。'+
'全角文字が含まれているとPythonEngineの初期化作業を行うことができません。'+#13#10+#13#10+
'全角文字を含まないPathに変更後、再度実行してください。',mtError,[mbOk],0);
//プログラムの終了
//Close; //止まらない!
Application.ShowMainForm:=False;
Application.Terminate; //停止するが、エラーが発生する
//halt; //停止するが、エラーが発生する
end else begin
//カーソルを待機状態にする
Screen.Cursor := crHourGlass;
・・・ 略 ・・・
end;
end;
contours = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]
num = len(contours)
mylist = np.zeros((num, 4))
i = 0
# red = (0, 0, 255)
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
# 高さが小さい場合は無視(ここを調整すれば設問番号を無視できる)
#if h < '+cmbStrHeight.Text+': <- Delphi埋め込み用
if h < 30:
mylist[i][0] = 0
mylist[i][1] = 0
mylist[i][2] = 0
mylist[i][3] = 0
else:
mylist[i][0] = x
mylist[i][1] = y
mylist[i][2] = x + w
mylist[i][3] = y + h
#cv2.rectangle(img, (x, y), (x+w, y+h), red, 2)
i += 1
どうやら元画像の「色が薄い」 or 「画像の線が太い」と問題が発生する傾向が強い気がしてきた。僕はこの実験に「えんぴつ」を使ったが、普通、試験時解答に使うのはシャーペンだから線が太くなることはあまり考えられない、むしろ、なるべく濃く書くことを注意事項に入れるべきかもしれない。なお、幅が狭くなっているように見えるのは、画像を強制的に幅64×高さ63にリサイズしているためだ。
//リソースに読み込んだ初期化用ファイルを再生
//ファイルの位置を指定
strFileName:=ExtractFilePath(Application.ExeName)+'imgAuto\tmp\maru.png';
//ファイルの存在を確認
if not FileExists(strFilename) then
begin
//リソースを再生
with TResourceStream.Create(hInstance, 'pngImage_1', RT_RCDATA) do
begin
try
SaveToFile(strFileName);
finally
Free;
end;
end;
end;
次に、Python Engineそのものを初期化。
//embPythonの存在の有無を調査
AppDataDir:=ExtractFilePath(Application.ExeName)+'Python39-64';
if DirectoryExists(AppDataDir) then
begin
//フォルダが存在したときの処理
PythonEngine1.AutoLoad := True;
PythonEngine1.IO := PythonGUIInputOutput1;
PythonEngine1.DllPath := AppDataDir;
PythonEngine1.SetPythonHome(PythonEngine1.DllPath);
PythonEngine1.LoadDll;
//PythonDelphiVar1のOnSeDataイベントを利用する
PythonDelphiVar1.Engine := PythonEngine1;
PythonDelphiVar1.VarName := AnsiString('var1');
//初期化
PythonEngine1.Py_Initialize;
end else begin
//MessageDlg('Python実行環境が見つかりません!',mtInformation,[mbOk], 0);
PythonEngine1.AutoLoad := False;
end;
最後に初期化用画像を読み込んで、1回だけ自動採点を実行する。
//スプラッシュ画面を表示してPython Engineを初期化
try
theSplashForm.Show;
theSplashForm.Refresh
//Scriptを入れるStringList
strScrList := TStringList.Create;
//結果を保存するStringList
strAnsList := TStringList.Create;
try
strScrList.Add('import json');
・・・略(自動採点用のPythonスクリプトをStringListに作成)・・・
//0による浮動小数除算の例外をマスクする
MaskFPUExceptions(True);
//Execute
PythonEngine1.ExecStrings(strScrList);
//先頭に認識した文字が入っている
if GetTokenIndex(strAnsList[0],',',0)='○' then
begin
//ShowMessage('The Python engine is now on standby!');
theSplashForm.StandbyLabel.Font.Color:=clBlue;
theSplashForm.StandbyLabel.Caption:='The P_Engine is now on standby!';
theSplashForm.StandbyLabel.Visible:=True;
Application.ProcessMessages;
//カウントダウン
for j:= 2 downto 1 do
begin
theSplashForm.TimeLabel.Caption:=Format('起動まであと%d秒', [j]);
Application.ProcessMessages;
Sleep(1000);
end;
end else begin
ShowMessage('Unable to initialize python engine!');
MessageDlg('Auto-scoring is not available!'+#13#10+
'Please contact your system administrator.',mtInformation,[mbOk],0);
end;
finally
//StringListの解放
strAnsList.Free;
strScrList.Free;
end;
finally
theSplashForm.Close;
theSplashForm.Destroy;
end;
これで「自動採点GroupBox」内の「実行」ボタンをクリックした際の処理が、ほぼ待ち時間なしで行われるようになった。これをやっておくのと、おかないのとでは、プログラムの使用感がまったく異なってくる・・・。上記のプログラムの for j := 2 downto 1 do 部分を「ムダ」だと思う方もいらっしゃるかもしれませんが、「画像の使用権を購入」してまで表示したスプラッシュ画面なので、せめて2秒間だけ!必要以上に長く表示させてください・・・。