How to create OMR template file (.omr) using existing image in Java

Hi @nikita.korobeynikov,

I am going to call TemplateProcessor.recognizeImage() method to process scanned image.

It takes String as file path but I get the image from BufferedImage in the memory.

In this case, can you please advise how to invoke method? In additon, is there any reference for API documenation?

Here is the snippet for your understanding.

// render the PDF page to an image with 100 DPI JPG format
BufferedImage image = renderer.renderImageWithDPI(i, 100, ImageType.RGB);
// Process the image using Aspose OMR
try {
// Create recognition results from the image, it throws the error as recognizeImage takes String path
RecognitionResult[] results = megaProcessor.recognizeImage(image);

Many thanks in advance.
Cheers,

Hello, @jamesanvictoria

Unfortunately, OMR Java supports only String input parameter at the moment.
I have added this feature into development queue and post detail here later on.

As a temporary workaround, I can recommend writing BufferedImage to file system:

        OmrEngine engine = new OmrEngine();
        //creating a temp file, using Java API
        File tempFile = File.createTempFile("OMR-Temp", ".png");
        //writing content of BufferedImage into temp file
        javax.imageio.ImageIO.write(bufferedImage, "png", tempFile);

        TemplateProcessor tp = engine.getTemplateProcessor(templatePath);
        //calling Recognize API using absolute path to temp file
        RecognitionResult rr = tp.recognizeImage(tempFile.getAbsolutePath(), 40);

Aspose OMR Java API located here - com.aspose.omr | Aspose.OMR for Java API Reference

Hi @nikita.korobeynikov
Understood. I stongly believe reading from memory directly is essential for future development so hopefully see any update for this soon.
By the way, I tested sample code but it prints out only parital part rather than the whole answer sheets.
For your information, here is the snippet what I wrote and the relavant results.

// process Mega/Revision sheet
private void processMega(String fileName){
// Use the file from static directory
String staticPath = “src/main/resources/static/assets/pdf/” + fileName;
// Process the file
RecognitionResult result = megaProcessor.recognizeImage(staticPath, 40);
System.out.println("getCsv() : " + result.getCsv());
System.out.println("getJson() : " + result.getJson());
System.out.println("getOmrElement() : " + result.getOmrElements());
System.out.println("getTemplateName() : " + result.getTemplateName());
}

===========================================================
getCsv() : Element Name,Value,
Question1,“B”
Question2,“C”
Question3,“C”
Question4,“B”
Question5,“A”

getJson() : {
“RecognitionResults”: [
{
“ElementName”: “Question1”,
“Value”: “B”
},
{
“ElementName”: “Question2”,
“Value”: “C”
},
{
“ElementName”: “Question3”,
“Value”: “C”
},
{
“ElementName”: “Question4”,
“Value”: “B”
},
{
“ElementName”: “Question5”,
“Value”: “A”
}
]
}
getOmrElement() : com.aspose.omr.lf.l0p@68573a6
getTemplateName() : For MEGA Revision_with_logo_2

FYI, I bought the liscent recently. (23/05/2025)

Hello, @jamesanvictoria

I agree that reading from memory is essential. I will add this feature ASAP - approximately in the next week as a new Java release.

Regarding missing questions, were there a line’s that sets license? For example:

        License license = new com.aspose.omr.License();
        license.setLicense("C:\\Users\\User\\Desktop\\OMR\\Aspose.OMR.Java.lic");

        OmrEngine engine = new OmrEngine();

These lines must be called each time application is Aspose OMR for Java is used, ideally before OmrEngine initialization.

Thank you so much for purchasing OMR for Java! I’m truly honored you chose our solution and sincerely hope it brings you great value and ease in your projects.

Hi @nikita.korobeynikov

Yes, I initialise license in the constructor block as below.

private OmrEngine engine;

private License omrLicense;

private TemplateProcessor megaProcessor;

private TemplateProcessor ttProcessor;


public OmrServiceImpl() {
omrLicense = new License();
try {
omrLicense.setLicense(“src/main/resources/omr/Aspose.OMR.Java.lic”);
} catch (Exception e) {
e.printStackTrace();
}
engine = new OmrEngine();
megaProcessor = engine.getTemplateProcessor(“src/main/resources/omr/MEGA.omr”);
ttProcessor = engine.getTemplateProcessor(“src/main/resources/omr/TT.omr”);
}

And confirmed license contains with xml tags

LicenseType : Developer OEM
LicenseNote :1 Developer And Unlimited Deployment Locations

Do I need to ask new license file?

Your feedback will be highly appreciated.

Screenshot 2025-06-19 at 9.30.08 am.png (91.8 KB)

@jamesanvictoria

Sorry to hear that there is an issue.
I have created a sample project for intellij IDEA, in attachment below. Is it working properly?
If sample project returning CSV with all questions - could you create an example project with this issue, that I could debug?
Thank you!

OMRJAVA-97-example-2.zip (2.8 MB)

Hi @nikita.korobeynikov

I could get proper result from your code with my purchased license so may not be an issue with purchased license.
However, when I ran my example (mega.jpg & mega.omr) under the same environment, it still generates only partial result (mega.csv).
Can you please confirm it ?
Many thanks to your co-work in advance.

OMRJAVA-Jin-example.zip (3.6 MB)

P.S> I realised it gets all question list - not only up to first 5 - even values are incorrect if I switch the aspose library from 24.5 to 24.12. (I guess values inconsistency might be based on wrong .omr file when I ran. I will verify this soon.)
Please see the scanned sheet and result csv the below.
Screenshot 2025-06-19 at 5.19.43 pm.jpg (203.8 KB)

Hello, @jamesanvictoria

Thank you for your patience!

I have investigated attached project.
Regarding licensing, your newly generated license is using a new encryption algorithm. Support for it was introduced in 24.12. So using it with earlier versions will result in licensing failure and limit to 5 first elements.

Regrading incorrect answers, I believe the issue is with a different .omr file.
mega.jpg was created using a “For MEGA Revision_with_logo”, but mega.omr is created for “For TT6 TT8 JMSS VSSE_with_logo”.
To verify, one can look at “Name” key inside .omr file content.

Also, I have noticed that student_number field were marked with smaller marks, like number “3”. I would recommend using a value of “30” for recognition threshold parameter to capture them.

Hi @nikita.korobeynikov

Thanks for your guide.

Yes, it works like a charm with 24.12 and I could get expected result with proper omr file. Thanks again.

In the meanwhile, is it possible to make group of result set?

For example, I have 3 subjects so want to make Group 1 [Q1~Q30] , Group 2 [Q1~Q30], Group 3 [Q1-Q30] rather than the whole list covering from Q1~Q90 like below.

getCsv() : Element Name,Value,
Question1,“B”
Question2,“C”
Question3,“C”
Question4,“B”
Question5,“A”
Question6,“B”
Question7,“B”
Question8,“D”
Question9,“C”
Question10,“C”
Question11,“C”
Question12,“C”
Question13,“A”
Question14,“B”
Question15,“A”
Question16,“A”
Question17,“B”
Question18,“B”
Question19,“D”
Question20,“D”
Question21,“D”
Question22,“”
Question23,“B”
Question24,“A”
Question25,“D”
Question26,“A”
Question27,“D”
Question28,“B”
Question29,“C”
Question30,“B”
Question31,“B”
Question32,“B”
Question33,“A”
Question34,“A”
Question35,“B”
Question36,“C”
Question37,“D”
Question38,“”
Question39,“C”
Question40,“A”
Question41,“B”
Question42,“B”
Question43,“B”
Question44,“D”
Question45,“C”
Question46,“B”
Question47,“B”
Question48,“D”
Question49,“D”
Question50,“A”
Question51,“D”
Question52,“C”
Question53,“B”
Question54,“D”
Question55,“C”
Question56,“B”
Question57,“A”
Question58,“B”
Question59,“”
Question60,“”
Question61,“D”
Question62,“C”
Question63,“D”
Question64,“D”
Question65,“D”
Question66,“A”
Question67,“A”
Question68,“D”
Question69,“B”
Question70,“B”
Question71,“A”
Question72,“C”
Question73,“D”
Question74,“D”
Question75,“C”
Question76,“B”
Question77,“A”
Question78,“C”
Question79,“A”
Question80,“C”
Question81,“A”
Question82,“C”
Question83,“A,C”
Question84,“B”
Question85,“”
Question86,“C”
Question87,“A”
Question88,“C”
Question89,“”
Question90,“B”

mega.pdf (1.7 MB)

I think almost get there thanks to your heaps of help !

@jamesanvictoria

I have updated each .omr file. Divided them into 2 and 3 groups:
Group_1_Q1 - Group_3_Q30
Group_1_Q1 - Group_2_Q60

Added .jpeg version of template I used for reference.
OMRJAVA-97-3.zip (8.3 MB)

Glad to be of assistance!

Hi @nikita.korobeynikov

Awesome — thank you so much for your continued support!

Your work has saved us a great deal of time on our side.

I’d like to ask for some advice regarding the recognizeImage(String imagePath, int recognitionThreshold) method.

I’m still not entirely clear on what the ideal threshold value should be, so I’ve been using 30, based on your earlier recommendation.

However, with this setting, it appears that some answers — specifically from the 6th and 7th sheets in my sample file — were not recognized.

Could you please advise how I might adjust the threshold to ensure all answers are included?

tt_10.zip (3.0 MB)

FYI, I am using ‘For TT6 TT8 JMSS VSSE_with_logo.omr’ template for this.

Cheers,

Hi @nikita.korobeynikov

Just to keep you informed — I’ve identified an issue during testing.

It appears that the student number was incorrectly recognized as “1,33476432” instead of the expected “13476432”.

Due to this formatting (with the comma), the system throws a NumberFormatException when attempting to convert the value to a long.

tt_10-page-006.pdf (319.7 KB)

Here is the output for debugging.

ElementName: Group_2_Q60, Value: E
ElementName: Student_number, Value: 1,33476432
Error parsing OMR results: For input string: “1,33476432”

Hello, @jamesanvictoria

Sorry to hear about this issue. I will debug it and post results here.

@jamesanvictoria

I have tested 6th page recognition with “For TT6 TT8 JMSS VSSE_with_logo.omr” template.
In a Windows environment, both JSON and CSV version return Student_number without commas.
I will debug this issue in macOS environment as well and post results here.

To help my investigation of this issue, can you please share values of “String csv,” “byte[] csvBytes” variables?
Does the issue persist in both csv and json results?

Regarding threshold value - it depends on marking instructions for student. Fully marked circle require 40, if partially marked bubbles are allowed - I could recommend go as low as 30.
I would not recommend lower values - as they could lead to false-positives.

Windows results of recognition - OMRJAVA-97-3.7z (2.6 MB)
I have used this Java code for template recognition and result saving:

        OmrEngine engine = new OmrEngine();

        TemplateProcessor tp = engine.getTemplateProcessor(templatePath);
        RecognitionResult rr = tp.recognizeImage(imagePath, 30);


        OpenOption oo = StandardOpenOption.CREATE;

        String csv = rr.getCsv();
        byte[] csvBytes = csv.getBytes();
        java.nio.file.Path cPath = Paths.get(csvPath);
        Files.write(cPath, csvBytes, oo);

        String json = rr.getJson();
        byte[] jsonBytes = json.getBytes();
        java.nio.file.Path jPath = Paths.get(jsonPath);
        Files.write(jPath, jsonBytes, oo);

Hi @nikita.korobeynikov

I used Json - getJson() - but for your debugging purpose, I slightly change the code like below.
Both result files show invalid studentId. (1,33476432)

result.zip (2.8 KB)

	RecognitionResult processResult = ttProcessor.recognizeImage(filePath, 30);			
	String jsonResult = processResult.getJson();

	// System.out.println("getJson() : " + jsonResult);
	// System.out.println("getCsv() : " + processResult.getCsv());

	OpenOption oo = StandardOpenOption.CREATE;

    String csv = processResult.getCsv();
    byte[] csvBytes = csv.getBytes();
    java.nio.file.Path cPath = Paths.get("src/main/resources/static/assets/pdf/csv.txt");
    try {
		Files.write(cPath, csvBytes, oo);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

    String json = processResult.getJson();
    byte[] jsonBytes = json.getBytes();
    java.nio.file.Path jPath = Paths.get("src/main/resources/static/assets/pdf/json.txt");
    try {
		Files.write(jPath, jsonBytes, oo);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

Can you please test new omr file only for student ID part and see how it goes?

Cheers,

Hello, @jamesanvictoria

I am sorry for the delay. We are working to resolve this issue as fast as possible.

I have tested .omr file with only student_id element. Unfortunately, the result is the same - no extra comma’s. Results of recognition below.
OMRJAVA-97-4.zip (2.3 MB)

I am planning to investigate and assert a solution for this issue in macOS environment as well.
The fix will be included in the next Java release, including BufferedImage support.
I have to postpone Java release for one week, please understand.

I will post progress here.

Thank you for your patience!

Hi @nikita.korobeynikov,

Thanks for your following up.

FYI, I am getting proper student ID by adjusting threshold from 30 to 32. Therefore, I think you don’t need to spend more time for investigating extra comma issue.

However, it would be definately great if we get BuffredImage support so let’s see how it goes.

Cheers,

Hello, @jamesanvictoria

I am glad that a temporary workaround were found! BufferedImage and Java release is in the queue for the next week.
Thank you for your patience! I will post details on progress in this thread.

Hello, @jamesanvictoria

I have prepared a 25.7 release of Aspose OMR for Java, with support for BufferedImage and InputStream.

Please share your feedback on this release.
Thank you.

Hi @nikita.korobeynikov

Thank you very much for your support !!

Could you please share any documentation or a code snippet demonstating how to create a sample using BufferedImage and InputStream in Java?

For your information, here is the code how I am using at the moment.

// render the PDF page to an image with 200 DPI JPG format
BufferedImage image = renderer.renderImageWithDPI(i, 200, ImageType.RGB);
// Use ByteArrayOutputStream to hold the image data in memory
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, “jpg”, baos);
byte[] imageBytes = baos.toByteArray();

==> No worries, I could figure it out. Will test more and see how it goes.

Cheers,