Input:
import com.dawex.sigourney.trustframework.vc.core.Proof;
import com.dawex.sigourney.trustframework.vc.core.SignedObject;
import com.dawex.sigourney.trustframework.vc.core.jsonld.annotation.JsonLdContexts;
import com.dawex.sigourney.trustframework.vc.core.jsonld.serialization.FormatProvider;
import com.dawex.sigourney.trustframework.vc.core.jsonld.serialization.JsonLdContextsSerializer;
import com.dawex.sigourney.trustframework.vc.core.jsonld.serialization.JsonLdSerializer;
import com.dawex.sigourney.trustframework.vc.core.jsonld.serialization.SignedObjectJsonLdSerializer;
import com.dawex.sigourney.trustframework.vc.model.shared.Did;
import com.dawex.sigourney.trustframework.vc.model.shared.JsonWebKey2020;
import com.dawex.sigourney.trustframework.vc.model.shared.VerifiablePresentation;
import com.dawex.sigourney.trustframework.vc.model.v2210.common.Address;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataproduct.AggregationOf;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataproduct.DataAccountExport;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataproduct.DataProductCredentialSubject;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataproduct.DataProductVerifiableCredential;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataproduct.ProvidedBy;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataproduct.TermsAndConditionURI;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataresource.DataResourceVerifiableCredential;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataresource.Distribution;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataresource.ProducedBy;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataresource.DataResourceCredentialSubject;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataresource.ExposedThrough;
import com.dawex.sigourney.trustframework.vc.model.v2210.dataresource.Location;
import com.dawex.sigourney.trustframework.vc.model.v2210.organisation.OrganisationCredentialSubject;
import com.dawex.sigourney.trustframework.vc.model.v2210.organisation.OrganisationLegalRegistrationNumber;
import com.dawex.sigourney.trustframework.vc.model.v2210.organisation.OrganisationVerifiableCredential;
import com.dawex.sigourney.trustframework.vc.model.v2210.termsandconditions.TermsAndConditionsCredentialSubject;
import com.dawex.sigourney.trustframework.vc.model.v2210.termsandconditions.TermsAndConditionsVerifiableCredential;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.util.List;
import java.util.function.Supplier;

Context:
trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/serialization/JacksonModuleFactory.java
package com.dawex.sigourney.trustframework.vc.model.v2210.serialization;

public class JacksonModuleFactory {

	/**
	 * Create a configured Jackson module for serializing organisation verifiable credentials
	 */
	public static Module organisationSerializationModule(FormatProvider formatProvider, Supplier<String> baseIriSupplier) {
		final List<Class> domainClasses = List.of(Address.class,
				OrganisationCredentialSubject.class,

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataresource/Distribution.java
public class Distribution {
	@JsonLdProperty(value = "title", namespace = Namespace.DAWEX_NS, mandatory = true)
	private final String title;

	@JsonLdProperty(value = "mediaType", namespace = Namespace.DAWEX_NS, mandatory = true)
	private final String mediaType;

	@JsonLdProperty(value = "byteSize", namespace = Namespace.DAWEX_NS, mandatory = true)
	private final Long byteSize;

	@JsonLdProperty(value = "fileHash", namespace = Namespace.DAWEX_NS, mandatory = true)
	private final String fileHash;

	@JsonLdProperty(value = "algorithm", namespace = Namespace.DAWEX_NS, mandatory = true)
	private final String algorithm;

	@JsonLdProperty(value = "location", namespace = Namespace.DAWEX_NS)
	private final Location location;

	public Distribution(String title, String mediaType, Long byteSize, String fileHash, String algorithm,
			Location location) {
		this.title = title;
		this.mediaType = mediaType;
		this.byteSize = byteSize;
		this.fileHash = fileHash;
		this.algorithm = algorithm;
		this.location = location;
	}

	public static DistributionBuilder builder() {
		return new DistributionBuilder();
	}

	public String getTitle() {
		return title;
	}

	public String getMediaType() {
		return mediaType;
	}

	public Long getByteSize() {
		return byteSize;
	}

	public String getFileHash() {
		return fileHash;
	}

	public String getAlgorithm() {
		return algorithm;
	}

	public Location getLocation() {
		return location;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		Distribution that = (Distribution) o;
		return Objects.equals(title, that.title) && Objects.equals(mediaType, that.mediaType) &&
				Objects.equals(byteSize, that.byteSize) && Objects.equals(fileHash, that.fileHash) &&
				Objects.equals(algorithm, that.algorithm) && Objects.equals(location, that.location);
	}

	@Override
	public int hashCode() {
		return Objects.hash(title, mediaType, byteSize, fileHash, algorithm, location);
	}

	@Override
	public String toString() {
		return "Distribution{" +
				"title='" + title + '\'' +
				", mediaType='" + mediaType + '\'' +
				", byteSize=" + byteSize +
				", fileHash='" + fileHash + '\'' +
				", algorithm='" + algorithm + '\'' +
				", location=" + location +
				'}';
	}

	public static class DistributionBuilder {
		private String title;

		private String mediaType;

		private Long byteSize;

		private String fileHash;

		private String algorithm;

		private Location location;

		DistributionBuilder() {
		}

		public DistributionBuilder title(String title) {
			this.title = title;
			return this;
		}

		public DistributionBuilder mediaType(String mediaType) {
			this.mediaType = mediaType;
			return this;
		}

		public DistributionBuilder byteSize(Long byteSize) {
			this.byteSize = byteSize;
			return this;
		}

		public DistributionBuilder fileHash(String fileHash) {
			this.fileHash = fileHash;
			return this;
		}

		public DistributionBuilder algorithm(String algorithm) {
			this.algorithm = algorithm;
			return this;
		}

		public DistributionBuilder location(Location location) {
			this.location = location;
			return this;
		}

		public Distribution build() {
			return new Distribution(title, mediaType, byteSize, fileHash, algorithm, location);
		}

		@Override
		public String toString() {
			return "DistributionBuilder{" +
					"title='" + title + '\'' +
					", mediaType='" + mediaType + '\'' +
					", byteSize=" + byteSize +
					", fileHash='" + fileHash + '\'' +
					", algorithm='" + algorithm + '\'' +
					", location=" + location +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataresource/ProducedBy.java
public class ProducedBy {
	@JsonLdProperty(value = "id", formatName = DATA_RESOURCE_PRODUCED_BY)
	private final String id;

	public ProducedBy(String id) {
		this.id = id;
	}

	public static ProducedByBuilder builder() {
		return new ProducedByBuilder();
	}

	public String getId() {
		return id;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		ProducedBy that = (ProducedBy) o;
		return Objects.equals(id, that.id);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id);
	}

	@Override
	public String toString() {
		return "ProducedBy{" +
				"id='" + id + '\'' +
				'}';
	}

	public static class ProducedByBuilder {
		private String id;

		ProducedByBuilder() {
		}

		public ProducedByBuilder id(String id) {
			this.id = id;
			return this;
		}

		public ProducedBy build() {
			return new ProducedBy(id);
		}

		@Override
		public String toString() {
			return "ProducedByBuilder{" +
					"id='" + id + '\'' +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-core/src/main/java/com/dawex/sigourney/trustframework/vc/core/jsonld/serialization/JsonLdContextsSerializer.java
public class JsonLdContextsSerializer extends JsonSerializer<JsonLdContexts> {

	private static final String CONTEXT_BASE = "@base";

	private Supplier<String> baseIri;

	public JsonLdContextsSerializer(Supplier<String> baseIri) {
		this.baseIri = baseIri;
	}

	@Override
	public void serialize(JsonLdContexts jsonLdContexts, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
			throws IOException {
		jsonGenerator.writeStartArray();
		writeEmbeddedContexts(jsonLdContexts, jsonGenerator);
		writeReferencedContexts(jsonLdContexts, jsonGenerator);
		jsonGenerator.writeEndArray();
	}

	private void writeEmbeddedContexts(JsonLdContexts jsonLdContexts, JsonGenerator jsonGenerator) throws IOException {
		if ((!jsonLdContexts.addBaseContext() || baseIri == null) && jsonLdContexts.embeddedContexts().length == 0) {
			return;
		}

		jsonGenerator.writeStartObject();
		if (jsonLdContexts.addBaseContext() && baseIri != null) {
			jsonGenerator.writeStringField(CONTEXT_BASE, baseIri.get());
		}
		for (JsonLdEmbeddedContext embeddedContext : jsonLdContexts.embeddedContexts()) {
			jsonGenerator.writeStringField(embeddedContext.term(), embeddedContext.iri());
		}
		jsonGenerator.writeEndObject();
	}

	private static void writeReferencedContexts(JsonLdContexts jsonLdContexts, JsonGenerator jsonGenerator) throws IOException {
		for (String referencedContext : jsonLdContexts.referencedContexts()) {
			jsonGenerator.writeString(referencedContext);
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/organisation/OrganisationCredentialSubject.java
@JsonLdType("gx:LegalParticipant")
public class OrganisationCredentialSubject {
	@JsonLdProperty(value = "id", formatName = Format.ORGANISATION_CREDENTIAL_SUBJECT)
	private final String id;

	@JsonLdProperty(value = "name", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final String name;

	@JsonLdProperty(value = "legalRegistrationNumber", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final OrganisationLegalRegistrationNumber registrationNumber;

	@JsonLdProperty(value = "headquarterAddress", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final Address headquarterAddress;

	@JsonLdProperty(value = "legalAddress", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final Address legalAddress;

	public OrganisationCredentialSubject(String id, String name, OrganisationLegalRegistrationNumber registrationNumber,
			Address headquarterAddress, Address legalAddress) {
		this.id = id;
		this.name = name;
		this.registrationNumber = registrationNumber;
		this.headquarterAddress = headquarterAddress;
		this.legalAddress = legalAddress;
	}

	public static OrganisationCredentialSubjectBuilder builder() {
		return new OrganisationCredentialSubjectBuilder();
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public OrganisationLegalRegistrationNumber getRegistrationNumber() {
		return registrationNumber;
	}

	public Address getHeadquarterAddress() {
		return headquarterAddress;
	}

	public Address getLegalAddress() {
		return legalAddress;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj == null || obj.getClass() != this.getClass()) {
			return false;
		}
		var that = (OrganisationCredentialSubject) obj;
		return Objects.equals(this.id, that.id) &&
				Objects.equals(this.name, that.name) &&
				Objects.equals(this.registrationNumber, that.registrationNumber) &&
				Objects.equals(this.headquarterAddress, that.headquarterAddress) &&
				Objects.equals(this.legalAddress, that.legalAddress);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id, name, registrationNumber, headquarterAddress, legalAddress);
	}

	@Override
	public String toString() {
		return "OrganisationCredentialSubject[" +
				"id=" + id + ", " +
				"name=" + name + ", " +
				"registrationNumber=" + registrationNumber + ", " +
				"headquarterAddress=" + headquarterAddress + ", " +
				"legalAddress=" + legalAddress + ']';
	}

	public static class OrganisationCredentialSubjectBuilder {
		private String id;

		private String name;

		private OrganisationLegalRegistrationNumber registrationNumber;

		private Address headquarterAddress;

		private Address legalAddress;

		OrganisationCredentialSubjectBuilder() {
		}

		public OrganisationCredentialSubjectBuilder id(String id) {
			this.id = id;
			return this;
		}

		public OrganisationCredentialSubjectBuilder name(String name) {
			this.name = name;
			return this;
		}

		public OrganisationCredentialSubjectBuilder registrationNumber(OrganisationLegalRegistrationNumber registrationNumber) {
			this.registrationNumber = registrationNumber;
			return this;
		}

		public OrganisationCredentialSubjectBuilder headquarterAddress(Address headquarterAddress) {
			this.headquarterAddress = headquarterAddress;
			return this;
		}

		public OrganisationCredentialSubjectBuilder legalAddress(Address legalAddress) {
			this.legalAddress = legalAddress;
			return this;
		}

		public OrganisationCredentialSubject build() {
			return new OrganisationCredentialSubject(id, name, registrationNumber, headquarterAddress, legalAddress);
		}

		@Override
		public String toString() {
			return "OrganisationCredentialSubjectBuilder{" +
					"id='" + id + '\'' +
					", name='" + name + '\'' +
					", registrationNumber='" + registrationNumber + '\'' +
					", headquarterAddress=" + headquarterAddress +
					", legalAddress=" + legalAddress +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/shared/VerifiablePresentation.java
@JsonLdContexts(referencedContexts = {VERIFIABLE_CREDENTIALS})
@JsonLdType("VerifiablePresentation")
public class VerifiablePresentation {

	@JsonLdProperty(value = "verifiableCredential")
	private final Collection<Object> verifiableCredential;

	public VerifiablePresentation(Collection<Object> verifiableCredential) {
		this.verifiableCredential = verifiableCredential;
	}

	public Collection<Object> getVerifiableCredential() {
		return verifiableCredential;
	}

	public static VerifiablePresentationBuilder builder() {
		return new VerifiablePresentationBuilder();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		VerifiablePresentation that = (VerifiablePresentation) o;
		return Objects.equals(verifiableCredential, that.verifiableCredential);
	}

	@Override
	public int hashCode() {
		return Objects.hash(verifiableCredential);
	}

	@Override
	public String toString() {
		return "VerifiablePresentation{" +
				"verifiableCredential=" + verifiableCredential +
				'}';
	}

	public static class VerifiablePresentationBuilder {
		private Collection<Object> verifiableCredential;

		VerifiablePresentationBuilder() {
		}

		public VerifiablePresentationBuilder verifiableCredential(Collection<Object> verifiableCredential) {
			this.verifiableCredential = verifiableCredential;
			return this;
		}

		public VerifiablePresentation build() {
			return new VerifiablePresentation(this.verifiableCredential);
		}

		@Override
		public String toString() {
			return "VerifiablePresentationBuilder{" +
					"verifiableCredential=" + verifiableCredential +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataresource/DataResourceCredentialSubject.java
@JsonLdType("gx:DataResource")
public class DataResourceCredentialSubject {
	@JsonLdProperty(value = "id", formatName = Format.DATA_RESOURCE_CREDENTIAL_SUBJECT)
	private final String id;

	@JsonLdProperty(value = "name", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS)
	private final String name;

	@JsonLdProperty(value = "description", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS)
	private final String description;

	@JsonLdProperty(value = "policy", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final Collection<String> policy;

	@JsonLdProperty(value = "license", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final Collection<String> licenses;

	@JsonLdProperty(value = "copyrightOwnedBy", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, formatName = Format.DATA_RESOURCE_COPYRIGHT_OWNED_BY, mandatory = true)
	private final Collection<String> copyrightOwnedBy;

	@JsonLdProperty(value = "producedBy", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final ProducedBy producedBy;

	@JsonLdProperty(value = "containsPII", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final boolean containsPII;

	@JsonLdProperty(value = "exposedThrough", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final ExposedThrough exposedThrough;

	@JsonLdProperty(value = "distribution", namespace = Namespace.DAWEX_NS)
	private final Distribution distribution;

	public DataResourceCredentialSubject(String id, String name, String description, Collection<String> policy, Collection<String> licenses,
			Collection<String> copyrightOwnedBy, ProducedBy producedBy, boolean containsPII, ExposedThrough exposedThrough,
			Distribution distribution) {
		this.id = id;
		this.name = name;
		this.description = description;
		this.policy = policy;
		this.licenses = licenses;
		this.copyrightOwnedBy = copyrightOwnedBy;
		this.producedBy = producedBy;
		this.containsPII = containsPII;
		this.exposedThrough = exposedThrough;
		this.distribution = distribution;
	}

	public static DataResourceCredentialSubjectBuilder builder() {
		return new DataResourceCredentialSubjectBuilder();
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public Collection<String> getPolicy() {
		return policy;
	}

	public Collection<String> getLicenses() {
		return licenses;
	}

	public Collection<String> getCopyrightOwnedBy() {
		return copyrightOwnedBy;
	}

	public ProducedBy getProducedBy() {
		return producedBy;
	}

	public boolean getContainsPII() {
		return containsPII;
	}

	public ExposedThrough getExposedThrough() {
		return exposedThrough;
	}

	public Distribution getDistribution() {
		return distribution;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		DataResourceCredentialSubject that = (DataResourceCredentialSubject) o;
		return containsPII == that.containsPII && Objects.equals(id, that.id) && Objects.equals(name, that.name) &&
				Objects.equals(description, that.description) && Objects.equals(policy, that.policy) &&
				Objects.equals(licenses, that.licenses) && Objects.equals(copyrightOwnedBy, that.copyrightOwnedBy) &&
				Objects.equals(producedBy, that.producedBy) && Objects.equals(exposedThrough, that.exposedThrough) &&
				Objects.equals(distribution, that.distribution);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id, name, description, policy, licenses, copyrightOwnedBy, producedBy, containsPII, exposedThrough,
				distribution);
	}

	@Override
	public String toString() {
		return "DataResourceCredentialSubject{" +
				"id='" + id + '\'' +
				", name='" + name + '\'' +
				", description='" + description + '\'' +
				", policy=" + policy +
				", licenses=" + licenses +
				", copyrightOwnedBy=" + copyrightOwnedBy +
				", producedBy=" + producedBy +
				", containsPII=" + containsPII +
				", exposedThrough=" + exposedThrough +
				", distribution=" + distribution +
				'}';
	}

	public static class DataResourceCredentialSubjectBuilder {
		private String id;

		private String name;

		private String description;

		private Collection<String> policy;

		private Collection<String> licenses;

		private Collection<String> copyrightOwnedBy;

		private ProducedBy producedBy;

		private boolean containsPII;

		private ExposedThrough exposedThrough;

		private Distribution distribution;

		DataResourceCredentialSubjectBuilder() {
		}

		public DataResourceCredentialSubjectBuilder id(String id) {
			this.id = id;
			return this;
		}

		public DataResourceCredentialSubjectBuilder name(String name) {
			this.name = name;
			return this;
		}

		public DataResourceCredentialSubjectBuilder description(String description) {
			this.description = description;
			return this;
		}

		public DataResourceCredentialSubjectBuilder policy(Collection<String> policy) {
			this.policy = policy;
			return this;
		}

		public DataResourceCredentialSubjectBuilder licenses(Collection<String> licenses) {
			this.licenses = licenses;
			return this;
		}

		public DataResourceCredentialSubjectBuilder copyrightOwnedBy(Collection<String> copyrightOwnedBy) {
			this.copyrightOwnedBy = copyrightOwnedBy;
			return this;
		}

		public DataResourceCredentialSubjectBuilder producedBy(ProducedBy producedBy) {
			this.producedBy = producedBy;
			return this;
		}

		public DataResourceCredentialSubjectBuilder containsPII(boolean containsPII) {
			this.containsPII = containsPII;
			return this;
		}

		public DataResourceCredentialSubjectBuilder exposedThrough(ExposedThrough exposedThrough) {
			this.exposedThrough = exposedThrough;
			return this;
		}

		public DataResourceCredentialSubjectBuilder distribution(Distribution distribution) {
			this.distribution = distribution;
			return this;
		}

		public DataResourceCredentialSubject build() {
			return new DataResourceCredentialSubject(id, name, description, policy, licenses, copyrightOwnedBy, producedBy, containsPII,
					exposedThrough, distribution);
		}

		@Override
		public String toString() {
			return "DataResourceCredentialSubjectBuilder{" +
					"id='" + id + '\'' +
					", name='" + name + '\'' +
					", description='" + description + '\'' +
					", policy=" + policy +
					", licenses=" + licenses +
					", copyrightOwnedBy=" + copyrightOwnedBy +
					", producedBy=" + producedBy +
					", containsPII=" + containsPII +
					", exposedThrough=" + exposedThrough +
					", distribution=" + distribution +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-core/src/main/java/com/dawex/sigourney/trustframework/vc/core/jsonld/serialization/SignedObjectJsonLdSerializer.java
public class SignedObjectJsonLdSerializer extends JsonLdSerializer<SignedObject> {

	public SignedObjectJsonLdSerializer(FormatProvider formatProvider) {
		super(SignedObject.class, formatProvider);
	}

	@Override
	public void serialize(SignedObject value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
		final Class<?> serializablePayloadClass = value.payload().getClass();
		jsonGenerator.writeStartObject();
		writeContext(serializablePayloadClass, jsonGenerator);
		writeType(serializablePayloadClass, jsonGenerator);
		writeJsonLdProperties(value.payload(), serializablePayloadClass, jsonGenerator);
		writeJsonLdProperties(value, SignedObject.class, jsonGenerator);
		jsonGenerator.writeEndObject();
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataresource/ExposedThrough.java
public class ExposedThrough {
	@JsonLdProperty(value = "id", formatName = Format.DATA_RESOURCE_EXPOSED_THROUGH)
	private final String id;

	public ExposedThrough(String id) {
		this.id = id;
	}

	public static ExposedThroughBuilder builder() {
		return new ExposedThroughBuilder();
	}

	public String getId() {
		return id;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		ExposedThrough that = (ExposedThrough) o;
		return Objects.equals(id, that.id);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id);
	}

	@Override
	public String toString() {
		return "ExposedThrough{" +
				"id='" + id + '\'' +
				'}';
	}

	public static class ExposedThroughBuilder {
		private String id;

		ExposedThroughBuilder() {
		}

		public ExposedThroughBuilder id(String id) {
			this.id = id;
			return this;
		}

		public ExposedThrough build() {
			return new ExposedThrough(id);
		}

		@Override
		public String toString() {
			return "ExposedThroughBuilder{" +
					"id='" + id + '\'' +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/organisation/OrganisationVerifiableCredential.java
@JsonLdContexts(
		addBaseContext = true,
		referencedContexts = {
				VERIFIABLE_CREDENTIALS,
				SECURITY_JWS_2020,
				GAIAX_TRUST_FRAMEWORK
		})
@JsonLdType("VerifiableCredential")
public class OrganisationVerifiableCredential {
	@JsonLdProperty(value = "id", formatName = Format.ORGANISATION_VERIFIABLE_CREDENTIAL)
	private final String id;

	@JsonLdProperty(value = "issuer", formatName = Format.ORGANISATION_ISSUER)
	private final String issuer;

	@JsonLdProperty(value = "issuanceDate")
	private final ZonedDateTime issuanceDate;

	@JsonLdProperty(value = "credentialSubject")
	private final OrganisationCredentialSubject organisationCredentialSubject;

	public OrganisationVerifiableCredential(String id, String issuer, ZonedDateTime issuanceDate,
			OrganisationCredentialSubject organisationCredentialSubject) {
		this.id = id;
		this.issuer = issuer;
		this.issuanceDate = issuanceDate;
		this.organisationCredentialSubject = organisationCredentialSubject;
	}

	public static OrganisationVerifiableCredentialBuilder builder() {
		return new OrganisationVerifiableCredentialBuilder();
	}

	public String getId() {
		return id;
	}

	public String getIssuer() {
		return issuer;
	}

	public ZonedDateTime getIssuanceDate() {
		return issuanceDate;
	}

	public OrganisationCredentialSubject getOrganisationCredentialSubject() {
		return organisationCredentialSubject;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj == null || obj.getClass() != this.getClass()) {
			return false;
		}
		var that = (OrganisationVerifiableCredential) obj;
		return Objects.equals(this.id, that.id) &&
				Objects.equals(this.issuer, that.issuer) &&
				Objects.equals(this.issuanceDate, that.issuanceDate) &&
				Objects.equals(this.organisationCredentialSubject, that.organisationCredentialSubject);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id, issuer, issuanceDate, organisationCredentialSubject);
	}

	@Override
	public String toString() {
		return "OrganisationVerifiableCredential[" +
				"id=" + id + ", " +
				"issuer=" + issuer + ", " +
				"issuanceDate=" + issuanceDate + ", " +
				"organisationCredentialSubject=" + organisationCredentialSubject + ']';
	}

	public static class OrganisationVerifiableCredentialBuilder {
		private String id;

		private String issuer;

		private ZonedDateTime issuanceDate;

		private OrganisationCredentialSubject organisationCredentialSubject;

		OrganisationVerifiableCredentialBuilder() {
		}

		public OrganisationVerifiableCredentialBuilder id(String id) {
			this.id = id;
			return this;
		}

		public OrganisationVerifiableCredentialBuilder issuer(String issuer) {
			this.issuer = issuer;
			return this;
		}

		public OrganisationVerifiableCredentialBuilder issuanceDate(ZonedDateTime issuanceDate) {
			this.issuanceDate = issuanceDate;
			return this;
		}

		public OrganisationVerifiableCredentialBuilder organisationCredentialSubject(
				OrganisationCredentialSubject organisationCredentialSubject) {
			this.organisationCredentialSubject = organisationCredentialSubject;
			return this;
		}

		public OrganisationVerifiableCredential build() {
			return new OrganisationVerifiableCredential(id, issuer, issuanceDate, organisationCredentialSubject);
		}

		@Override
		public String toString() {
			return "OrganisationVerifiableCredentialBuilder{" +
					"id='" + id + '\'' +
					", issuer='" + issuer + '\'' +
					", issuanceDate=" + issuanceDate +
					", organisationCredentialSubject=" + organisationCredentialSubject +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataproduct/ProvidedBy.java
public class ProvidedBy {
	@JsonLdProperty(value = "id", formatName = DATA_PRODUCT_PROVIDED_BY)
	private final String id;

	public ProvidedBy(String id) {
		this.id = id;
	}

	public static ProvidedByBuilder builder() {
		return new ProvidedByBuilder();
	}

	public String getId() {
		return id;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		ProvidedBy that = (ProvidedBy) o;
		return Objects.equals(id, that.id);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id);
	}

	@Override
	public String toString() {
		return "ProvidedBy{" +
				"id='" + id + '\'' +
				'}';
	}

	public static class ProvidedByBuilder {
		private String id;

		ProvidedByBuilder() {
		}

		public ProvidedByBuilder id(String id) {
			this.id = id;
			return this;
		}

		public ProvidedBy build() {
			return new ProvidedBy(id);
		}

		@Override
		public String toString() {
			return "ProvidedByBuilder{" +
					"id='" + id + '\'' +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataproduct/TermsAndConditionURI.java
public class TermsAndConditionURI {
	@JsonLdProperty(value = "URL", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, formatName = DATA_PRODUCT_TERMS_AND_CONDITIONS_URI, mandatory = true)
	private final String url;

	@JsonLdProperty(value = "hash", namespace = Namespace.GAIAX_TRUST_FRAMEWORK_NS, mandatory = true)
	private final String hash;

	public TermsAndConditionURI(String url, String hash) {
		this.url = url;
		this.hash = hash;
	}

	public static TermsAndConditionURIBuilder builder() {
		return new TermsAndConditionURIBuilder();
	}

	public String getUrl() {
		return url;
	}

	public String getHash() {
		return hash;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		TermsAndConditionURI that = (TermsAndConditionURI) o;
		return Objects.equals(url, that.url) && Objects.equals(hash, that.hash);
	}

	@Override
	public int hashCode() {
		return Objects.hash(url, hash);
	}

	@Override
	public String toString() {
		return "TermsAndConditionURI{" +
				"url='" + url + '\'' +
				", hash='" + hash + '\'' +
				'}';
	}

	public static class TermsAndConditionURIBuilder {
		private String url;

		private String hash;

		TermsAndConditionURIBuilder() {
		}

		public TermsAndConditionURIBuilder url(String url) {
			this.url = url;
			return this;
		}

		public TermsAndConditionURIBuilder hash(String hash) {
			this.hash = hash;
			return this;
		}

		public TermsAndConditionURI build() {
			return new TermsAndConditionURI(url, hash);
		}

		@Override
		public String toString() {
			return "TermsAndConditionURIBuilder{" +
					"url='" + url + '\'' +
					", hash='" + hash + '\'' +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataresource/Location.java
public class Location {
	@JsonLdProperty(value = "dataCenterLocation", namespace = Namespace.DAWEX_NS)
	private final String dataCenterLocation;

	public Location(String dataCenterLocation) {
		this.dataCenterLocation = dataCenterLocation;
	}

	public static LocationBuilder builder() {
		return new LocationBuilder();
	}

	public String getDataCenterLocation() {
		return dataCenterLocation;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj == null || obj.getClass() != this.getClass()) {
			return false;
		}
		var that = (Location) obj;
		return Objects.equals(this.dataCenterLocation, that.dataCenterLocation);
	}

	@Override
	public int hashCode() {
		return Objects.hash(dataCenterLocation);
	}

	@Override
	public String toString() {
		return "Location[" +
				"dataCenterLocation=" + dataCenterLocation + ']';
	}

	public static class LocationBuilder {
		private String dataCenterLocation;

		LocationBuilder() {
		}

		public LocationBuilder dataCenterLocation(String dataCenterLocation) {
			this.dataCenterLocation = dataCenterLocation;
			return this;
		}

		public Location build() {
			return new Location(dataCenterLocation);
		}

		@Override
		public String toString() {
			return "LocationBuilder{" +
					"dataCenterLocation='" + dataCenterLocation + '\'' +
					'}';
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/v2210/dataproduct/DataProductVerifiableCredential.java
@JsonLdContexts(
		addBaseContext = true,
		embeddedContexts = {
				@JsonLdEmbeddedContext(term = Namespace.DC_TERMS_NS, iri = Namespace.DC_TERMS_IRI),
		},
		referencedContexts = {
				VERIFIABLE_CREDENTIALS,
				SECURITY_JWS_2020,
				GAIAX_TRUST_FRAMEWORK
		})
@JsonLdType("VerifiableCredential")
public class DataProductVerifiableCredential {
	@JsonLdProperty(value = "id", formatName = DATA_PRODUCT_VERIFIABLE_CREDENTIAL)
	private final Id id;

	@JsonLdProperty(value = "issuer", formatName = DATA_PRODUCT_ISSUER)
	private final String issuer;

	@JsonLdProperty(value = "issuanceDate")
	private final ZonedDateTime issuanceDate;

	@JsonLdProperty(value = "credentialSubject")
	private final DataProductCredentialSubject credentialSubject;

	public DataProductVerifiableCredential(Id id, String issuer, ZonedDateTime issuanceDate,
			DataProductCredentialSubject credentialSubject) {
		this.id = id;
		this.issuer = issuer;
		this.issuanceDate = issuanceDate;
		this.credentialSubject = credentialSubject;
	}

	public static DataProductVerifiableCredentialBuilder builder() {
		return new DataProductVerifiableCredentialBuilder();
	}

	public Id getId() {
		return id;
	}

	public String getIssuer() {
		return issuer;
	}

	public ZonedDateTime getIssuanceDate() {
		return issuanceDate;
	}

	public DataProductCredentialSubject getCredentialSubject() {
		return credentialSubject;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj == null || obj.getClass() != this.getClass()) {
			return false;
		}
		var that = (DataProductVerifiableCredential) obj;
		return Objects.equals(this.id, that.id) &&
				Objects.equals(this.issuer, that.issuer) &&
				Objects.equals(this.issuanceDate, that.issuanceDate) &&
				Objects.equals(this.credentialSubject, that.credentialSubject);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id, issuer, issuanceDate, credentialSubject);
	}

	@Override
	public String toString() {
		return "DataProductVerifiableCredential[" +
				"id=" + id + ", " +
				"issuer=" + issuer + ", " +
				"issuanceDate=" + issuanceDate + ", " +
				"credentialSubject=" + credentialSubject + ']';
	}

	public static class DataProductVerifiableCredentialBuilder {
		private Id id;

		private String issuer;

		private ZonedDateTime issuanceDate;

		private DataProductCredentialSubject credentialSubject;

		DataProductVerifiableCredentialBuilder() {
		}

		public DataProductVerifiableCredentialBuilder id(Id id) {
			this.id = id;
			return this;
		}

		public DataProductVerifiableCredentialBuilder issuer(String issuer) {
			this.issuer = issuer;
			return this;
		}

		public DataProductVerifiableCredentialBuilder issuanceDate(ZonedDateTime issuanceDate) {
			this.issuanceDate = issuanceDate;
			return this;
		}

		public DataProductVerifiableCredentialBuilder credentialSubject(DataProductCredentialSubject credentialSubject) {
			this.credentialSubject = credentialSubject;
			return this;
		}

		public DataProductVerifiableCredential build() {
			return new DataProductVerifiableCredential(id, issuer, issuanceDate, credentialSubject);
		}

		@Override
		public String toString() {
			return "DataProductVerifiableCredentialBuilder{" +
					"id=" + id +
					", issuer='" + issuer + '\'' +
					", issuanceDate=" + issuanceDate +
					", credentialSubject=" + credentialSubject +
					'}';
		}
	}

	public record Id(String dataProductId, String organisationId) implements CompositeValue {
		@Override
		public Object[] getValues() {
			return new Object[]{organisationId, dataProductId};
		}
	}
}

trust-framework/verifiable-credentials-model/src/main/java/com/dawex/sigourney/trustframework/vc/model/shared/JsonWebKey2020.java
@JsonLdContexts(referencedContexts = SECURITY_JWS_2020)
@JsonLdType("JsonWebKey2020")
public class JsonWebKey2020 implements VerificationMethod {

	@JsonLdProperty(value = "id")
	private final String id;

	@JsonLdProperty(value = "controller")
	private final String controller;

	@JsonLdProperty(value = "publicKeyJwk")
	private final Map<String, Object> publicKeyJwk;

	public JsonWebKey2020(String id, String controller, Map<String, Object> publicKeyJwk) {
		this.id = id;
		this.controller = controller;
		this.publicKeyJwk = publicKeyJwk;
	}

	public String getId() {
		return id;
	}

	public String getController() {
		return controller;
	}

	public Map<String, Object> getPublicKeyJwk() {
		return publicKeyJwk;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		JsonWebKey2020 that = (JsonWebKey2020) o;
		return Objects.equals(id, that.id) && Objects.equals(controller, that.controller) &&
				Objects.equals(publicKeyJwk, that.publicKeyJwk);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id, controller, publicKeyJwk);
	}

	@Override
	public String toString() {
		return "JsonWebKey2020{" +
				"id='" + id + '\'' +
				", controller='" + controller + '\'' +
				", publicKeyJwk=" + publicKeyJwk +
				'}';
	}

	public static JsonWebKey2020Builder builder() {
		return new JsonWebKey2020Builder();
	}

	public static class JsonWebKey2020Builder {

		private String id;

		private String controller;

		private Map<String, Object> publicKeyJwk;

		JsonWebKey2020Builder() {
		}

		public JsonWebKey2020Builder id(String id) {
			this.id = id;
			return this;
		}

		public JsonWebKey2020Builder controller(String controller) {
			this.controller = controller;
			return this;
		}

		public JsonWebKey2020Builder publicKeyJwk(Map<String, Object> publicKeyJwk) {
			this.publicKeyJwk = publicKeyJwk;
			return this;
		}

		public JsonWebKey2020 build() {
			return new JsonWebKey2020(id, controller, publicKeyJwk);
		}

		@Override
		public String toString() {
			return "JsonWebKey2020Builder{" +
					"id='" + id + '\'' +
					", controller='" + controller + '\'' +
					", publicKeyJwk=" + publicKeyJwk +
					'}';
		}
	}
}

Answer: OrganisationLegalRegistrationNumber.class,

<think>
The method `organisationSerializationModule` starts building a list of domain classes to register with Jackson. The list already includes `Address.class` and `OrganisationCredentialSubject.class,` and the next class needed for organisation credential serialization is the registration number type. Therefore the next line adds `OrganisationLegalRegistrationNumber.class,` to the list.
</think>
OrganisationLegalRegistrationNumber.class,


Input:
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import torch
import torchvision
import matplotlib.pyplot as plt
import numpy as np
import torch
import torchvision
import matplotlib.pyplot as plt
import numpy as np
import torch
import torchvision
import matplotlib.pyplot as plt
import os; os.environ["CUDA_VISIBLE_DEVICES"]="0"
from PIL import Image
from mask_generator import SamMaskGenerator
from utils.utils import show_masks
from build_sam import sam_model_registry
from PIL import Image
from build_sam import sam_model_registry
from predictor import SamPredictor
from utils.utils import show_mask, show_box, show_points
from PIL import Image
from mask_generator import SamMaskGenerator
from utils.utils import show_mask, show_masks, show_points
from build_sam import sam_model_registry
from PIL import Image
from mask_generator import SamMaskGenerator
from utils.utils import show_mask, show_masks, show_points
from build_sam import sam_model_registry
from PIL import Image
from mask_generator import SamMaskGenerator
from utils.utils import show_mask, show_masks, show_points
from build_sam import sam_model_registry
from PIL import Image
from mask_generator import SamMaskGenerator
from utils.utils import show_mask, show_points, show_lbk_masks
from build_sam import sam_model_registry
from utils.amg import build_all_layer_point_grids

Context:
example.py
# %%
""" Example 1: All mask generation """
# basic module

sam = sam_model_registry['vit_b'](checkpoint='ckpt/sam_vit_b_01ec64.pth').cuda()
auto_to_mask = SamMaskGenerator(sam, stability_score_thresh=0.8)

# image upload
img = np.array(Image.open("figure/paris2.jpg"))
masks = auto_to_mask.generate(img)

# visualization
plt.figure(figsize=(20,20))
plt.imshow(img)
img = show_masks(masks, plt)
plt.axis('off')
plt.show()
""" End """
# %%
""" Example 2: Prompts -> one mask generation for one image """
sam = sam_model_registry['vit_b'](checkpoint='ckpt/sam_vit_b_01ec64.pth').cuda()
prompt_to_mask = SamPredictor(sam)

# image upload
img = np.array(Image.open("figure/paris2.jpg"))
prompt_to_mask.set_image(img)

# prompt
# input_point = np.array([[500, 375], [370, 1200]])
# input_label = np.array([1, 1])
# input_point = np.array([[370, 1200]])
# input_label = np.array([1])

input_box = np.array([200, 600, 500, 1400])

# visualization
plt.figure(figsize=(10,10))
plt.imshow(img)
show_box(input_box, plt.gca(), plt)
# show_points(input_point, input_label, plt.gca())
plt.axis('on')
plt.show()

# sam prediction
masks, scores, logits = prompt_to_mask.predict(
    box = input_box,
    multimask_output=True,
)

# image proposal
for i, (mask, score) in enumerate(zip(masks, scores)):
    plt.figure(figsize=(10,10))
    plt.imshow(img)
    show_mask(mask, plt.gca())
    show_box(input_box, plt.gca(), plt)
    # show_points(input_point, input_label, plt.gca())
    plt.title(f"Mask {i+1}, Score: {score:.3f}", fontsize=18)
    plt.axis('off')
    plt.show()
""" End """

# %%
""" Example 3: Individual prompt -> Multi-mask generation for one image """

build_sam.py
def build_sam_vit_h(checkpoint=None, custom_img_size=1024):
def build_sam_vit_l(checkpoint=None, custom_img_size=1024):
def build_sam_vit_b(checkpoint=None, custom_img_size=1024):
def _build_sam(
    encoder_embed_dim,
    encoder_depth,
    encoder_num_heads,
    encoder_global_attn_indexes,
    checkpoint=None,
    custom_img_size=1024, # by LBK EDIT
):
def build_sam_vit_t(checkpoint=None, custom_img_size=1024):

utils/utils.py
def show_mask(mask, ax, random_color=True):
    if random_color:
        color = np.concatenate([np.random.random(3), np.array([0.6])], axis=0)
    else:
        color = np.array([30/255, 144/255, 255/255, 0.6])
    h, w = mask.shape[-2:]
    mask_image = mask.reshape(h, w, 1) * color.reshape(1, 1, -1)
    ax.imshow(mask_image)

utils/utils.py
def show_points(coords, labels, ax, marker_size=50):
    pos_points = coords[labels==1]
    neg_points = coords[labels==0]
    ax.scatter(pos_points[:, 0], pos_points[:, 1], color='green', marker='o', s=marker_size, edgecolor='white', linewidth=1.25)
    ax.scatter(neg_points[:, 0], neg_points[:, 1], color='red', marker='o', s=marker_size, edgecolor='white', linewidth=1.25)

utils/utils.py
def show_masks(masks, plt, alpha=0.7):
    if len(masks) == 0: return
    sorted_masks = sorted(masks, key=(lambda x: x['area']), reverse=True)
    ax = plt.gca()
    ax.set_autoscale_on(False)

    img = np.ones((masks[0]['segmentation'].shape[0], masks[0]['segmentation'].shape[1], 4))
    img[:,:,3] = 0
    for ann in sorted_masks:
        m = ann['segmentation']
        color_mask = np.concatenate([np.random.random(3), [alpha]])
        img[m] = color_mask
    ax.imshow(img)
    return img

build_sam.py
def build_sam_vit_h(checkpoint=None, custom_img_size=1024):
def build_sam_vit_l(checkpoint=None, custom_img_size=1024):
def build_sam_vit_b(checkpoint=None, custom_img_size=1024):
def _build_sam(
    encoder_embed_dim,
    encoder_depth,
    encoder_num_heads,
    encoder_global_attn_indexes,
    checkpoint=None,
    custom_img_size=1024, # by LBK EDIT
):
def build_sam_vit_t(checkpoint=None, custom_img_size=1024):

mask_generator.py
class SamMaskGenerator:
    def __init__(
        self,
        model: Sam,
        points_per_side: Optional[int] = 32,
        points_per_batch: int = 64,
        pred_iou_thresh: float = 0.88,
        stability_score_thresh: float = 0.95,
        stability_score_offset: float = 1.0,
        box_nms_thresh: float = 0.7,
        crop_n_layers: int = 0,
        crop_nms_thresh: float = 0.7,
        crop_overlap_ratio: float = 512 / 1500,
        crop_n_points_downscale_factor: int = 1,
        point_grids: Optional[List[np.ndarray]] = None,
        min_mask_region_area: int = 0,
        output_mode: str = "binary_mask",
    ) -> None:
        """
        Using a SAM model, generates masks for the entire image.
        Generates a grid of point prompts over the image, then filters
        low quality and duplicate masks. The default settings are chosen
        for SAM with a ViT-H backbone.

        Arguments:
          model (Sam): The SAM model to use for mask prediction.
          points_per_side (int or None): The number of points to be sampled
            along one side of the image. The total number of points is
            points_per_side**2. If None, 'point_grids' must provide explicit
            point sampling.
          points_per_batch (int): Sets the number of points run simultaneously
            by the model. Higher numbers may be faster but use more GPU memory.
          pred_iou_thresh (float): A filtering threshold in [0,1], using the
            model's predicted mask quality.
          stability_score_thresh (float): A filtering threshold in [0,1], using
            the stability of the mask under changes to the cutoff used to binarize
            the model's mask predictions.
          stability_score_offset (float): The amount to shift the cutoff when
            calculated the stability score.
          box_nms_thresh (float): The box IoU cutoff used by non-maximal
            suppression to filter duplicate masks.
          crop_n_layers (int): If >0, mask prediction will be run again on
            crops of the image. Sets the number of layers to run, where each
            layer has 2**i_layer number of image crops.
          crop_nms_thresh (float): The box IoU cutoff used by non-maximal
            suppression to filter duplicate masks between different crops.
          crop_overlap_ratio (float): Sets the degree to which crops overlap.
            In the first crop layer, crops will overlap by this fraction of
            the image length. Later layers with more crops scale down this overlap.
          crop_n_points_downscale_factor (int): The number of points-per-side
            sampled in layer n is scaled down by crop_n_points_downscale_factor**n.
          point_grids (list(np.ndarray) or None): A list over explicit grids
            of points used for sampling, normalized to [0,1]. The nth grid in the
            list is used in the nth crop layer. Exclusive with points_per_side.
          min_mask_region_area (int): If >0, postprocessing will be applied
            to remove disconnected regions and holes in masks with area smaller
            than min_mask_region_area. Requires opencv.
          output_mode (str): The form masks are returned in. Can be 'binary_mask',
            'uncompressed_rle', or 'coco_rle'. 'coco_rle' requires pycocotools.
            For large resolutions, 'binary_mask' may consume large amounts of
            memory.
        """

        assert (points_per_side is None) != (
            point_grids is None
        ), "Exactly one of points_per_side or point_grid must be provided."
        if points_per_side is not None:
            self.point_grids = build_all_layer_point_grids(
                points_per_side,
                crop_n_layers,
                crop_n_points_downscale_factor,
            )
        elif point_grids is not None:
            self.point_grids = point_grids
        else:
            raise ValueError("Can't have both points_per_side and point_grid be None.")

        assert output_mode in [
            "binary_mask",
            "uncompressed_rle",
            "coco_rle",
        ], f"Unknown output_mode {output_mode}."
        if output_mode == "coco_rle":
            from pycocotools import mask as mask_utils  # type: ignore # noqa: F401

        if min_mask_region_area > 0:
            import cv2  # type: ignore # noqa: F401

        self.predictor = SamPredictor(model)
        self.points_per_batch = points_per_batch
        self.pred_iou_thresh = pred_iou_thresh
        self.stability_score_thresh = stability_score_thresh
        self.stability_score_offset = stability_score_offset
        self.box_nms_thresh = box_nms_thresh
        self.crop_n_layers = crop_n_layers
        self.crop_nms_thresh = crop_nms_thresh
        self.crop_overlap_ratio = crop_overlap_ratio
        self.crop_n_points_downscale_factor = crop_n_points_downscale_factor
        self.min_mask_region_area = min_mask_region_area
        self.output_mode = output_mode

    @torch.no_grad()
    def generate(self, image: np.ndarray) -> List[Dict[str, Any]]:
        """
        Generates masks for the given image.

        Arguments:
          image (np.ndarray): The image to generate masks for, in HWC uint8 format.

        Returns:
           list(dict(str, any)): A list over records for masks. Each record is
             a dict containing the following keys:
               segmentation (dict(str, any) or np.ndarray): The mask. If
                 output_mode='binary_mask', is an array of shape HW. Otherwise,
                 is a dictionary containing the RLE.
               bbox (list(float)): The box around the mask, in XYWH format.
               area (int): The area in pixels of the mask.
               predicted_iou (float): The model's own prediction of the mask's
                 quality. This is filtered by the pred_iou_thresh parameter.
               point_coords (list(list(float))): The point coordinates input
                 to the model to generate this mask.
               stability_score (float): A measure of the mask's quality. This
                 is filtered on using the stability_score_thresh parameter.
               crop_box (list(float)): The crop of the image used to generate
                 the mask, given in XYWH format.
        """

        # Generate masks
        mask_data = self._generate_masks(image)

        # Filter small disconnected regions and holes in masks
        if self.min_mask_region_area > 0:
            mask_data = self.postprocess_small_regions(
                mask_data,
                self.min_mask_region_area,
                max(self.box_nms_thresh, self.crop_nms_thresh),
            )

        # Encode masks
        if self.output_mode == "coco_rle":
            mask_data["segmentations"] = [coco_encode_rle(rle) for rle in mask_data["rles"]]
        elif self.output_mode == "binary_mask":
            mask_data["segmentations"] = [rle_to_mask(rle) for rle in mask_data["rles"]]
        else:
            mask_data["segmentations"] = mask_data["rles"]

        # Write mask records
        curr_anns = []
        for idx in range(len(mask_data["segmentations"])):
            ann = {
                "segmentation": mask_data["segmentations"][idx],
                "area": area_from_rle(mask_data["rles"][idx]),
                "bbox": box_xyxy_to_xywh(mask_data["boxes"][idx]).tolist(),
                "predicted_iou": mask_data["iou_preds"][idx].item(),
                "point_coords": [mask_data["points"][idx].tolist()],
                "stability_score": mask_data["stability_score"][idx].item(),
                "crop_box": box_xyxy_to_xywh(mask_data["crop_boxes"][idx]).tolist(),
            }
            curr_anns.append(ann)

        return curr_anns

    def _generate_masks(self, image: np.ndarray) -> MaskData:
        orig_size = image.shape[:2]
        crop_boxes, layer_idxs = generate_crop_boxes(
            orig_size, self.crop_n_layers, self.crop_overlap_ratio
        )

        # Iterate over image crops
        data = MaskData()
        for crop_box, layer_idx in zip(crop_boxes, layer_idxs):
            crop_data = self._process_crop(image, crop_box, layer_idx, orig_size)
            data.cat(crop_data)

        # Remove duplicate masks between crops
        if len(crop_boxes) > 1:
            # Prefer masks from smaller crops
            scores = 1 / box_area(data["crop_boxes"])
            scores = scores.to(data["boxes"].device)
            keep_by_nms = batched_nms(
                data["boxes"].float(),
                scores,
                torch.zeros_like(data["boxes"][:, 0]),  # categories
                iou_threshold=self.crop_nms_thresh,
            )
            data.filter(keep_by_nms)

        data.to_numpy()
        return data

    def _process_crop(
        self,
        image: np.ndarray,
        crop_box: List[int],
        crop_layer_idx: int,
        orig_size: Tuple[int, ...],
    ) -> MaskData:
        # Crop the image and calculate embeddings
        x0, y0, x1, y1 = crop_box
        cropped_im = image[y0:y1, x0:x1, :]
        cropped_im_size = cropped_im.shape[:2]
        self.predictor.set_image(cropped_im)

        # Get points for this crop
        points_scale = np.array(cropped_im_size)[None, ::-1]
        points_for_image = self.point_grids[crop_layer_idx] * points_scale

        # Generate masks for this crop in batches
        data = MaskData()
        for (points,) in batch_iterator(self.points_per_batch, points_for_image):
            batch_data = self._process_batch(points, cropped_im_size, crop_box, orig_size)
            data.cat(batch_data)
            del batch_data
        self.predictor.reset_image()

        # Remove duplicates within this crop.
        keep_by_nms = batched_nms(
            data["boxes"].float(),
            data["iou_preds"],
            torch.zeros_like(data["boxes"][:, 0]),  # categories
            iou_threshold=self.box_nms_thresh,
        )
        data.filter(keep_by_nms)

        # Return to the original image frame
        data["boxes"] = uncrop_boxes_xyxy(data["boxes"], crop_box)
        data["points"] = uncrop_points(data["points"], crop_box)
        data["crop_boxes"] = torch.tensor([crop_box for _ in range(len(data["rles"]))])

        return data

    def _process_batch(
        self,
        points: np.ndarray,
        im_size: Tuple[int, ...],
        crop_box: List[int],
        orig_size: Tuple[int, ...],
    ) -> MaskData:
        orig_h, orig_w = orig_size

        # Run model on this batch
        transformed_points = self.predictor.transform.apply_coords(points, im_size)
        in_points = torch.as_tensor(transformed_points, device=self.predictor.device)
        in_labels = torch.ones(in_points.shape[0], dtype=torch.int, device=in_points.device)
        masks, iou_preds, _ = self.predictor.predict_torch(
            in_points[:, None, :],
            in_labels[:, None],
            multimask_output=True,
            return_logits=True,
        )

        # Serialize predictions and store in MaskData
        data = MaskData(
            masks=masks.flatten(0, 1),
            iou_preds=iou_preds.flatten(0, 1),
            points=torch.as_tensor(points.repeat(masks.shape[1], axis=0)),
        )
        del masks

        # Filter by predicted IoU
        if self.pred_iou_thresh > 0.0:
            keep_mask = data["iou_preds"] > self.pred_iou_thresh
            data.filter(keep_mask)

        # Calculate stability score
        data["stability_score"] = calculate_stability_score(
            data["masks"], self.predictor.model.mask_threshold, self.stability_score_offset
        )
        if self.stability_score_thresh > 0.0:
            keep_mask = data["stability_score"] >= self.stability_score_thresh
            data.filter(keep_mask)

        # Threshold masks and calculate boxes
        data["masks"] = data["masks"] > self.predictor.model.mask_threshold
        data["boxes"] = batched_mask_to_box(data["masks"])

        # Filter boxes that touch crop boundaries
        keep_mask = ~is_box_near_crop_edge(data["boxes"], crop_box, [0, 0, orig_w, orig_h])
        if not torch.all(keep_mask):
            data.filter(keep_mask)

        # Compress to RLE
        data["masks"] = uncrop_masks(data["masks"], crop_box, orig_h, orig_w)
        data["rles"] = mask_to_rle_pytorch(data["masks"])
        del data["masks"]

        return data

    @staticmethod
    def postprocess_small_regions(
        mask_data: MaskData, min_area: int, nms_thresh: float
    ) -> MaskData:
        """
        Removes small disconnected regions and holes in masks, then reruns
        box NMS to remove any new duplicates.

        Edits mask_data in place.

        Requires open-cv as a dependency.
        """
        if len(mask_data["rles"]) == 0:
            return mask_data

        # Filter small disconnected regions and holes
        new_masks = []
        scores = []
        for rle in mask_data["rles"]:
            mask = rle_to_mask(rle)

            mask, changed = remove_small_regions(mask, min_area, mode="holes")
            unchanged = not changed
            mask, changed = remove_small_regions(mask, min_area, mode="islands")
            unchanged = unchanged and not changed

            new_masks.append(torch.as_tensor(mask).unsqueeze(0))
            # Give score=0 to changed masks and score=1 to unchanged masks
            # so NMS will prefer ones that didn't need postprocessing
            scores.append(float(unchanged))

        # Recalculate boxes and remove any new duplicates
        masks = torch.cat(new_masks, dim=0)
        boxes = batched_mask_to_box(masks)
        keep_by_nms = batched_nms(
            boxes.float(),
            torch.as_tensor(scores),
            torch.zeros_like(boxes[:, 0]),  # categories
            iou_threshold=nms_thresh,
        )

        # Only recalculate RLEs for masks that have changed
        for i_mask in keep_by_nms:
            if scores[i_mask] == 0.0:
                mask_torch = masks[i_mask].unsqueeze(0)
                mask_data["rles"][i_mask] = mask_to_rle_pytorch(mask_torch)[0]
                mask_data["boxes"][i_mask] = boxes[i_mask]  # update res directly
        mask_data.filter(keep_by_nms)

        return mask_data

    # Individual Prompting by LBK
    @torch.no_grad()
    def individual_generate(
        self,
        image: np.ndarray,
        points_for_image: np.array,
        ) -> List[Dict[str, Any]]:

        def _individual_process_crop(
            image: np.ndarray,
            img_box: List[int],
            orig_size: Tuple[int, ...],
        ) -> MaskData:
            # Crop the image and calculate embeddings
            im_size = image.shape[:2]
            self.predictor.set_image(image)

            # Generate masks for this crop in batches
            data = MaskData()
            for (points,) in batch_iterator(self.points_per_batch, points_for_image):
                batch_data = self._process_batch(points, im_size, img_box, orig_size)
                data.cat(batch_data)
                del batch_data
            self.predictor.reset_image()

            # Remove duplicates within this crop.
            keep_by_nms = batched_nms(
                data["boxes"].float(),
                data["iou_preds"],
                torch.zeros_like(data["boxes"][:, 0]),  # categories
                iou_threshold=self.box_nms_thresh,
            )
            data.filter(keep_by_nms)

            # Return to the original image frame
            data["boxes"] = uncrop_boxes_xyxy(data["boxes"], img_box)
            data["points"] = uncrop_points(data["points"], img_box)
            data["crop_boxes"] = torch.tensor([img_box for _ in range(len(data["rles"]))])

            return data

        def _individual_generate_masks(image: np.ndarray)-> MaskData:
            im_h, im_w = image.shape[:2]

            # Iterate over image crops
            data = MaskData()
            data.cat(_individual_process_crop(image, [0, 0, im_w, im_h], (im_h, im_w)))
            data.to_numpy()
            return data

        # Generate masks
        mask_data = _individual_generate_masks(image)

        # Filter small disconnected regions and holes in masks
        if self.min_mask_region_area > 0:
            mask_data = self.postprocess_small_regions(
                mask_data,
                self.min_mask_region_area,
                max(self.box_nms_thresh, self.crop_nms_thresh),
            )

        # Encode masks
        if self.output_mode == "coco_rle":
            mask_data["segmentations"] = [coco_encode_rle(rle) for rle in mask_data["rles"]]
        elif self.output_mode == "binary_mask":
            mask_data["segmentations"] = [rle_to_mask(rle) for rle in mask_data["rles"]]
        else:
            mask_data["segmentations"] = mask_data["rles"]

        # Write mask records
        curr_anns = []
        for idx in range(len(mask_data["segmentations"])):
            ann = {
                "segmentation": mask_data["segmentations"][idx],
                "area": area_from_rle(mask_data["rles"][idx]),
                "bbox": box_xyxy_to_xywh(mask_data["boxes"][idx]).tolist(),
                "predicted_iou": mask_data["iou_preds"][idx].item(),
                "point_coords": [mask_data["points"][idx].tolist()],
                "stability_score": mask_data["stability_score"][idx].item(),
                "crop_box": box_xyxy_to_xywh(mask_data["crop_boxes"][idx]).tolist(),
            }
            curr_anns.append(ann)

        return curr_anns

utils/utils.py
def show_lbk_masks(masks, plt, alpha=0.7):
    if len(masks) == 0: return
    ax = plt.gca()
    ax.set_autoscale_on(False)

    img = np.ones((masks.shape[1], masks.shape[2], 4))
    img[:,:,3] = 0
    for ann in masks:
        color_mask = np.concatenate([np.random.random(3), [alpha]])
        img[ann] = color_mask
    ax.imshow(img)
    return img

utils/utils.py
def show_points(coords, labels, ax, marker_size=50):
    pos_points = coords[labels==1]
    neg_points = coords[labels==0]
    ax.scatter(pos_points[:, 0], pos_points[:, 1], color='green', marker='o', s=marker_size, edgecolor='white', linewidth=1.25)
    ax.scatter(neg_points[:, 0], neg_points[:, 1], color='red', marker='o', s=marker_size, edgecolor='white', linewidth=1.25)

mask_generator.py
class SamMaskGenerator:
    def __init__(
        self,
        model: Sam,
        points_per_side: Optional[int] = 32,
        points_per_batch: int = 64,
        pred_iou_thresh: float = 0.88,
        stability_score_thresh: float = 0.95,
        stability_score_offset: float = 1.0,
        box_nms_thresh: float = 0.7,
        crop_n_layers: int = 0,
        crop_nms_thresh: float = 0.7,
        crop_overlap_ratio: float = 512 / 1500,
        crop_n_points_downscale_factor: int = 1,
        point_grids: Optional[List[np.ndarray]] = None,
        min_mask_region_area: int = 0,
        output_mode: str = "binary_mask",
    ) -> None:
        """
        Using a SAM model, generates masks for the entire image.
        Generates a grid of point prompts over the image, then filters
        low quality and duplicate masks. The default settings are chosen
        for SAM with a ViT-H backbone.

        Arguments:
          model (Sam): The SAM model to use for mask prediction.
          points_per_side (int or None): The number of points to be sampled
            along one side of the image. The total number of points is
            points_per_side**2. If None, 'point_grids' must provide explicit
            point sampling.
          points_per_batch (int): Sets the number of points run simultaneously
            by the model. Higher numbers may be faster but use more GPU memory.
          pred_iou_thresh (float): A filtering threshold in [0,1], using the
            model's predicted mask quality.
          stability_score_thresh (float): A filtering threshold in [0,1], using
            the stability of the mask under changes to the cutoff used to binarize
            the model's mask predictions.
          stability_score_offset (float): The amount to shift the cutoff when
            calculated the stability score.
          box_nms_thresh (float): The box IoU cutoff used by non-maximal
            suppression to filter duplicate masks.
          crop_n_layers (int): If >0, mask prediction will be run again on
            crops of the image. Sets the number of layers to run, where each
            layer has 2**i_layer number of image crops.
          crop_nms_thresh (float): The box IoU cutoff used by non-maximal
            suppression to filter duplicate masks between different crops.
          crop_overlap_ratio (float): Sets the degree to which crops overlap.
            In the first crop layer, crops will overlap by this fraction of
            the image length. Later layers with more crops scale down this overlap.
          crop_n_points_downscale_factor (int): The number of points-per-side
            sampled in layer n is scaled down by crop_n_points_downscale_factor**n.
          point_grids (list(np.ndarray) or None): A list over explicit grids
            of points used for sampling, normalized to [0,1]. The nth grid in the
            list is used in the nth crop layer. Exclusive with points_per_side.
          min_mask_region_area (int): If >0, postprocessing will be applied
            to remove disconnected regions and holes in masks with area smaller
            than min_mask_region_area. Requires opencv.
          output_mode (str): The form masks are returned in. Can be 'binary_mask',
            'uncompressed_rle', or 'coco_rle'. 'coco_rle' requires pycocotools.
            For large resolutions, 'binary_mask' may consume large amounts of
            memory.
        """

        assert (points_per_side is None) != (
            point_grids is None
        ), "Exactly one of points_per_side or point_grid must be provided."
        if points_per_side is not None:
            self.point_grids = build_all_layer_point_grids(
                points_per_side,
                crop_n_layers,
                crop_n_points_downscale_factor,
            )
        elif point_grids is not None:
            self.point_grids = point_grids
        else:
            raise ValueError("Can't have both points_per_side and point_grid be None.")

        assert output_mode in [
            "binary_mask",
            "uncompressed_rle",
            "coco_rle",
        ], f"Unknown output_mode {output_mode}."
        if output_mode == "coco_rle":
            from pycocotools import mask as mask_utils  # type: ignore # noqa: F401

        if min_mask_region_area > 0:
            import cv2  # type: ignore # noqa: F401

        self.predictor = SamPredictor(model)
        self.points_per_batch = points_per_batch
        self.pred_iou_thresh = pred_iou_thresh
        self.stability_score_thresh = stability_score_thresh
        self.stability_score_offset = stability_score_offset
        self.box_nms_thresh = box_nms_thresh
        self.crop_n_layers = crop_n_layers
        self.crop_nms_thresh = crop_nms_thresh
        self.crop_overlap_ratio = crop_overlap_ratio
        self.crop_n_points_downscale_factor = crop_n_points_downscale_factor
        self.min_mask_region_area = min_mask_region_area
        self.output_mode = output_mode

    @torch.no_grad()
    def generate(self, image: np.ndarray) -> List[Dict[str, Any]]:
        """
        Generates masks for the given image.

        Arguments:
          image (np.ndarray): The image to generate masks for, in HWC uint8 format.

        Returns:
           list(dict(str, any)): A list over records for masks. Each record is
             a dict containing the following keys:
               segmentation (dict(str, any) or np.ndarray): The mask. If
                 output_mode='binary_mask', is an array of shape HW. Otherwise,
                 is a dictionary containing the RLE.
               bbox (list(float)): The box around the mask, in XYWH format.
               area (int): The area in pixels of the mask.
               predicted_iou (float): The model's own prediction of the mask's
                 quality. This is filtered by the pred_iou_thresh parameter.
               point_coords (list(list(float))): The point coordinates input
                 to the model to generate this mask.
               stability_score (float): A measure of the mask's quality. This
                 is filtered on using the stability_score_thresh parameter.
               crop_box (list(float)): The crop of the image used to generate
                 the mask, given in XYWH format.
        """

        # Generate masks
        mask_data = self._generate_masks(image)

        # Filter small disconnected regions and holes in masks
        if self.min_mask_region_area > 0:
            mask_data = self.postprocess_small_regions(
                mask_data,
                self.min_mask_region_area,
                max(self.box_nms_thresh, self.crop_nms_thresh),
            )

        # Encode masks
        if self.output_mode == "coco_rle":
            mask_data["segmentations"] = [coco_encode_rle(rle) for rle in mask_data["rles"]]
        elif self.output_mode == "binary_mask":
            mask_data["segmentations"] = [rle_to_mask(rle) for rle in mask_data["rles"]]
        else:
            mask_data["segmentations"] = mask_data["rles"]

        # Write mask records
        curr_anns = []
        for idx in range(len(mask_data["segmentations"])):
            ann = {
                "segmentation": mask_data["segmentations"][idx],
                "area": area_from_rle(mask_data["rles"][idx]),
                "bbox": box_xyxy_to_xywh(mask_data["boxes"][idx]).tolist(),
                "predicted_iou": mask_data["iou_preds"][idx].item(),
                "point_coords": [mask_data["points"][idx].tolist()],
                "stability_score": mask_data["stability_score"][idx].item(),
                "crop_box": box_xyxy_to_xywh(mask_data["crop_boxes"][idx]).tolist(),
            }
            curr_anns.append(ann)

        return curr_anns

    def _generate_masks(self, image: np.ndarray) -> MaskData:
        orig_size = image.shape[:2]
        crop_boxes, layer_idxs = generate_crop_boxes(
            orig_size, self.crop_n_layers, self.crop_overlap_ratio
        )

        # Iterate over image crops
        data = MaskData()
        for crop_box, layer_idx in zip(crop_boxes, layer_idxs):
            crop_data = self._process_crop(image, crop_box, layer_idx, orig_size)
            data.cat(crop_data)

        # Remove duplicate masks between crops
        if len(crop_boxes) > 1:
            # Prefer masks from smaller crops
            scores = 1 / box_area(data["crop_boxes"])
            scores = scores.to(data["boxes"].device)
            keep_by_nms = batched_nms(
                data["boxes"].float(),
                scores,
                torch.zeros_like(data["boxes"][:, 0]),  # categories
                iou_threshold=self.crop_nms_thresh,
            )
            data.filter(keep_by_nms)

        data.to_numpy()
        return data

    def _process_crop(
        self,
        image: np.ndarray,
        crop_box: List[int],
        crop_layer_idx: int,
        orig_size: Tuple[int, ...],
    ) -> MaskData:
        # Crop the image and calculate embeddings
        x0, y0, x1, y1 = crop_box
        cropped_im = image[y0:y1, x0:x1, :]
        cropped_im_size = cropped_im.shape[:2]
        self.predictor.set_image(cropped_im)

        # Get points for this crop
        points_scale = np.array(cropped_im_size)[None, ::-1]
        points_for_image = self.point_grids[crop_layer_idx] * points_scale

        # Generate masks for this crop in batches
        data = MaskData()
        for (points,) in batch_iterator(self.points_per_batch, points_for_image):
            batch_data = self._process_batch(points, cropped_im_size, crop_box, orig_size)
            data.cat(batch_data)
            del batch_data
        self.predictor.reset_image()

        # Remove duplicates within this crop.
        keep_by_nms = batched_nms(
            data["boxes"].float(),
            data["iou_preds"],
            torch.zeros_like(data["boxes"][:, 0]),  # categories
            iou_threshold=self.box_nms_thresh,
        )
        data.filter(keep_by_nms)

        # Return to the original image frame
        data["boxes"] = uncrop_boxes_xyxy(data["boxes"], crop_box)
        data["points"] = uncrop_points(data["points"], crop_box)
        data["crop_boxes"] = torch.tensor([crop_box for _ in range(len(data["rles"]))])

        return data

    def _process_batch(
        self,
        points: np.ndarray,
        im_size: Tuple[int, ...],
        crop_box: List[int],
        orig_size: Tuple[int, ...],
    ) -> MaskData:
        orig_h, orig_w = orig_size

        # Run model on this batch
        transformed_points = self.predictor.transform.apply_coords(points, im_size)
        in_points = torch.as_tensor(transformed_points, device=self.predictor.device)
        in_labels = torch.ones(in_points.shape[0], dtype=torch.int, device=in_points.device)
        masks, iou_preds, _ = self.predictor.predict_torch(
            in_points[:, None, :],
            in_labels[:, None],
            multimask_output=True,
            return_logits=True,
        )

        # Serialize predictions and store in MaskData
        data = MaskData(
            masks=masks.flatten(0, 1),
            iou_preds=iou_preds.flatten(0, 1),
            points=torch.as_tensor(points.repeat(masks.shape[1], axis=0)),
        )
        del masks

        # Filter by predicted IoU
        if self.pred_iou_thresh > 0.0:
            keep_mask = data["iou_preds"] > self.pred_iou_thresh
            data.filter(keep_mask)

        # Calculate stability score
        data["stability_score"] = calculate_stability_score(
            data["masks"], self.predictor.model.mask_threshold, self.stability_score_offset
        )
        if self.stability_score_thresh > 0.0:
            keep_mask = data["stability_score"] >= self.stability_score_thresh
            data.filter(keep_mask)

        # Threshold masks and calculate boxes
        data["masks"] = data["masks"] > self.predictor.model.mask_threshold
        data["boxes"] = batched_mask_to_box(data["masks"])

        # Filter boxes that touch crop boundaries
        keep_mask = ~is_box_near_crop_edge(data["boxes"], crop_box, [0, 0, orig_w, orig_h])
        if not torch.all(keep_mask):
            data.filter(keep_mask)

        # Compress to RLE
        data["masks"] = uncrop_masks(data["masks"], crop_box, orig_h, orig_w)
        data["rles"] = mask_to_rle_pytorch(data["masks"])
        del data["masks"]

        return data

    @staticmethod
    def postprocess_small_regions(
        mask_data: MaskData, min_area: int, nms_thresh: float
    ) -> MaskData:
        """
        Removes small disconnected regions and holes in masks, then reruns
        box NMS to remove any new duplicates.

        Edits mask_data in place.

        Requires open-cv as a dependency.
        """
        if len(mask_data["rles"]) == 0:
            return mask_data

        # Filter small disconnected regions and holes
        new_masks = []
        scores = []
        for rle in mask_data["rles"]:
            mask = rle_to_mask(rle)

            mask, changed = remove_small_regions(mask, min_area, mode="holes")
            unchanged = not changed
            mask, changed = remove_small_regions(mask, min_area, mode="islands")
            unchanged = unchanged and not changed

            new_masks.append(torch.as_tensor(mask).unsqueeze(0))
            # Give score=0 to changed masks and score=1 to unchanged masks
            # so NMS will prefer ones that didn't need postprocessing
            scores.append(float(unchanged))

        # Recalculate boxes and remove any new duplicates
        masks = torch.cat(new_masks, dim=0)
        boxes = batched_mask_to_box(masks)
        keep_by_nms = batched_nms(
            boxes.float(),
            torch.as_tensor(scores),
            torch.zeros_like(boxes[:, 0]),  # categories
            iou_threshold=nms_thresh,
        )

        # Only recalculate RLEs for masks that have changed
        for i_mask in keep_by_nms:
            if scores[i_mask] == 0.0:
                mask_torch = masks[i_mask].unsqueeze(0)
                mask_data["rles"][i_mask] = mask_to_rle_pytorch(mask_torch)[0]
                mask_data["boxes"][i_mask] = boxes[i_mask]  # update res directly
        mask_data.filter(keep_by_nms)

        return mask_data

    # Individual Prompting by LBK
    @torch.no_grad()
    def individual_generate(
        self,
        image: np.ndarray,
        points_for_image: np.array,
        ) -> List[Dict[str, Any]]:

        def _individual_process_crop(
            image: np.ndarray,
            img_box: List[int],
            orig_size: Tuple[int, ...],
        ) -> MaskData:
            # Crop the image and calculate embeddings
            im_size = image.shape[:2]
            self.predictor.set_image(image)

            # Generate masks for this crop in batches
            data = MaskData()
            for (points,) in batch_iterator(self.points_per_batch, points_for_image):
                batch_data = self._process_batch(points, im_size, img_box, orig_size)
                data.cat(batch_data)
                del batch_data
            self.predictor.reset_image()

            # Remove duplicates within this crop.
            keep_by_nms = batched_nms(
                data["boxes"].float(),
                data["iou_preds"],
                torch.zeros_like(data["boxes"][:, 0]),  # categories
                iou_threshold=self.box_nms_thresh,
            )
            data.filter(keep_by_nms)

            # Return to the original image frame
            data["boxes"] = uncrop_boxes_xyxy(data["boxes"], img_box)
            data["points"] = uncrop_points(data["points"], img_box)
            data["crop_boxes"] = torch.tensor([img_box for _ in range(len(data["rles"]))])

            return data

        def _individual_generate_masks(image: np.ndarray)-> MaskData:
            im_h, im_w = image.shape[:2]

            # Iterate over image crops
            data = MaskData()
            data.cat(_individual_process_crop(image, [0, 0, im_w, im_h], (im_h, im_w)))
            data.to_numpy()
            return data

        # Generate masks
        mask_data = _individual_generate_masks(image)

        # Filter small disconnected regions and holes in masks
        if self.min_mask_region_area > 0:
            mask_data = self.postprocess_small_regions(
                mask_data,
                self.min_mask_region_area,
                max(self.box_nms_thresh, self.crop_nms_thresh),
            )

        # Encode masks
        if self.output_mode == "coco_rle":
            mask_data["segmentations"] = [coco_encode_rle(rle) for rle in mask_data["rles"]]
        elif self.output_mode == "binary_mask":
            mask_data["segmentations"] = [rle_to_mask(rle) for rle in mask_data["rles"]]
        else:
            mask_data["segmentations"] = mask_data["rles"]

        # Write mask records
        curr_anns = []
        for idx in range(len(mask_data["segmentations"])):
            ann = {
                "segmentation": mask_data["segmentations"][idx],
                "area": area_from_rle(mask_data["rles"][idx]),
                "bbox": box_xyxy_to_xywh(mask_data["boxes"][idx]).tolist(),
                "predicted_iou": mask_data["iou_preds"][idx].item(),
                "point_coords": [mask_data["points"][idx].tolist()],
                "stability_score": mask_data["stability_score"][idx].item(),
                "crop_box": box_xyxy_to_xywh(mask_data["crop_boxes"][idx]).tolist(),
            }
            curr_anns.append(ann)

        return curr_anns

Answer: sam = sam_model_registry['vit_b'](checkpoint='ckpt/sam_vit_b_01ec64.pth').cuda()

<think>
After the series of import statements, the next logical step is to instantiate the SAM model using the imported sam_model_registry, as done in the example scripts. This creates the model object needed for subsequent mask generation.
</think>
sam = sam_model_registry['vit_b'](checkpoint='ckpt/sam_vit_b_01ec64.pth').cuda()